diff --git a/.envrc b/.envrc
index 3550a30..29da48d 100644
--- a/.envrc
+++ b/.envrc
@@ -1 +1,2 @@
+watch_file shell.nix
use flake
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..6751428
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,20 @@
+{
+ "env": {
+ "browser": true,
+ "es2021": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module"
+ },
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "rules": {
+ }
+}
diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml
index 7b25262..2d862b0 100644
--- a/.github/actions/build-test-image/action.yml
+++ b/.github/actions/build-test-image/action.yml
@@ -22,9 +22,11 @@ inputs:
runs:
using: composite
steps:
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
- name: Check if image exists
id: check-image
- uses: goplugin/plugin-github-actions/docker/image-exists@8489879838862929f43f7d7cd1b33903965cf507 # v2.1.6
+ uses: goplugin/plugin-github-actions/docker/image-exists@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
repository: plugin-starknet-tests
tag: ${{ inputs.tag }}
@@ -32,7 +34,7 @@ runs:
AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }}
- name: Build and Publish Test Runner
if: steps.check-image.outputs.exists == 'false'
- uses: goplugin/plugin-github-actions/docker/build-push@8489879838862929f43f7d7cd1b33903965cf507 # v2.1.6
+ uses: goplugin/plugin-github-actions/docker/build-push@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
tags: |
${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/plugin-starknet-tests:${{ inputs.tag }}
diff --git a/.github/actions/install-cairo/action.yml b/.github/actions/install-cairo/action.yml
new file mode 100644
index 0000000..d3f1524
--- /dev/null
+++ b/.github/actions/install-cairo/action.yml
@@ -0,0 +1,33 @@
+name: Install Cairo and Scarb
+description: A composite action that installs cairo and scarb binaries
+
+inputs:
+ cairo_version:
+ description: Cairo release version
+ default: "v2.6.4"
+ required: false
+ scarb_version:
+ description: Scarb release version
+ default: "v2.6.5"
+ required: false
+
+runs:
+ using: composite
+ steps:
+ - name: Setup Cairo for Linux
+ id: install-cairo
+ shell: bash
+ run: |
+ wget https://github.com/starkware-libs/cairo/releases/download/${{ inputs.cairo_version }}/release-x86_64-unknown-linux-musl.tar.gz
+ tar -xvzf release-x86_64-unknown-linux-musl.tar.gz
+ mv -vf cairo cairo-build
+ echo "$GITHUB_WORKSPACE/cairo-build/bin" >> $GITHUB_PATH
+
+ - name: Setup Scarb for Linux
+ id: install-scarb
+ shell: bash
+ run: |
+ wget https://github.com/software-mansion/scarb/releases/download/${{ inputs.scarb_version }}/scarb-${{ inputs.scarb_version }}-x86_64-unknown-linux-musl.tar.gz
+ tar -xvzf scarb-${{ inputs.scarb_version }}-x86_64-unknown-linux-musl.tar.gz
+ mv -vf scarb-${{ inputs.scarb_version }}-x86_64-unknown-linux-musl scarb-build
+ echo "$GITHUB_WORKSPACE/scarb-build/bin" >> $GITHUB_PATH
diff --git a/.github/actions/install-starknet-foundry/action.yml b/.github/actions/install-starknet-foundry/action.yml
new file mode 100644
index 0000000..8e4360e
--- /dev/null
+++ b/.github/actions/install-starknet-foundry/action.yml
@@ -0,0 +1,18 @@
+name: Install Starknet Foundry (snforge and sncast)
+description: A composite action that installs the snforge and sncast binaries
+
+inputs:
+ starknet_foundry_version:
+ description: Starknet Foundry release version
+ default: "0.27.0"
+ required: false
+
+runs:
+ using: composite
+ steps:
+ - name: Setup Starknet Foundry for Linux
+ id: install-starknet-foundry
+ shell: bash
+ run: |
+ curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh
+ snfoundryup -v ${{ inputs.starknet_foundry_version }}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..ec19129
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/amarna.yml b/.github/workflows/amarna.yml
deleted file mode 100644
index 13c11f0..0000000
--- a/.github/workflows/amarna.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: Amarna Analysis
-on:
- push:
- branches:
- - develop
- - main
- pull_request:
-
-jobs:
- analyze:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
- - name: Run Amarna
- uses: crytic/amarna-action@v0.1.1
- id: amarna
- continue-on-error: true
- with:
- amarna-args: --disable-inline --exclude-rules=must-check-caller-address
- sarif: results.sarif
- target: 'contracts/src/plugin/cairo/'
-
- - name: Upload SARIF file
- uses: github/codeql-action/upload-sarif@v2
- with:
- sarif_file: ${{ steps.amarna.outputs.sarif }}
- checkout_path: '/github/workspace'
diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml
index e8df7b7..f502099 100644
--- a/.github/workflows/changesets.yml
+++ b/.github/workflows/changesets.yml
@@ -12,14 +12,14 @@ jobs:
steps:
# Checkout this repository
- name: Checkout Repo
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
# Install nix
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
# Install dependencies using yarn
@@ -27,7 +27,7 @@ jobs:
run: nix develop -c yarn install --frozen-lockfile
# Create PR that will update versions or trigger publish
- name: Create Release Pull Request
- uses: changesets/action@2a025e8ab1cfa4312c2868cb6aa3cd3b473b84bf # v1.3.0
+ uses: changesets/action@aba318e9165b45b7948c60273e0b72fce0a64eb9 # v1.4.7
id: changesets
with:
publish: nix develop -c yarn release
diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml
index 7ba39e7..d10fdfd 100644
--- a/.github/workflows/contracts.yml
+++ b/.github/workflows/contracts.yml
@@ -8,17 +8,41 @@ on:
pull_request:
jobs:
- contracts_run_tests:
- name: Run Tests
+ contracts_run_ts_tests:
+ name: Run Typescript Tests
runs-on: ubuntu-latest
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+
- name: Test
run: nix develop -c make test-ts-contracts
+
+ contracts_run_cairo_tests:
+ name: Run Cairo Tests
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
+ - name: Install Nix
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+
+ - name: Install Starknet Foundry
+ uses: ./.github/actions/install-starknet-foundry
+
+ - name: Test
+ run: nix develop -c make test-cairo-contracts
diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml
new file mode 100644
index 0000000..4a15c9c
--- /dev/null
+++ b/.github/workflows/examples.yml
@@ -0,0 +1,30 @@
+name: Example Contracts
+
+on:
+ push:
+ branches:
+ - develop
+ - main
+ pull_request:
+
+jobs:
+ run_examples_tests:
+ name: Run Tests
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
+ - name: Install Nix
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+
+ - name: Install Starknet Foundry
+ uses: ./.github/actions/install-starknet-foundry
+
+ - name: Test
+ run: nix develop -c make test-examples
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index df48e23..978a59c 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -9,9 +9,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Parse version
@@ -31,13 +31,22 @@ jobs:
needs: [golangci-lint-version]
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Lint relayer
run: nix develop -c make lint-go-relayer
+ - name: Print Report
+ if: failure()
+ run: cat ./relayer/golangci-lint-relayer-report.xml
+ - name: Store Golangci lint relayer report artifact
+ if: always()
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ with:
+ name: golangci-lint-relayer-report
+ path: ./relayer/golangci-lint-relayer-report.xml
golang_lint_ops:
name: Golang Lint Ops
@@ -45,13 +54,22 @@ jobs:
needs: [golangci-lint-version]
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Lint ops
run: nix develop -c make lint-go-ops
+ - name: Print Report
+ if: failure()
+ run: cat ./ops/golangci-lint-ops-report.xml
+ - name: Store Golangci lint ops report artifact
+ if: always()
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ with:
+ name: golangci-lint-ops-report
+ path: ./ops/golangci-lint-ops-report.xml
golang_lint_integration_tests:
name: Golang Lint Integration Tests
@@ -59,13 +77,22 @@ jobs:
needs: [golangci-lint-version]
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Lint integration-tests
run: nix develop -c make lint-go-test
+ - name: Print Report
+ if: failure()
+ run: cat ./integration-tests/golangci-lint-integration-tests-report.xml
+ - name: Store Golangci lint integration tests report artifact
+ if: always()
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ with:
+ name: golangci-lint-integration-tests-report
+ path: ./integration-tests/golangci-lint-integration-tests-report.xml
# Note: I could not figure out why the golangci-lint-action would not work even though it is technically running the same as above, error message is this:
# Running [/home/runner/golangci-lint-1.50.1-linux-amd64/golangci-lint run --out-format=github-actions --path-prefix=integration-tests --exclude=dot-imports] in [/home/runner/work/plugin-starknet/plugin-starknet/integration-tests] ...
# level=warning msg="[runner] Can't run linter goanalysis_metalinter: inspect: failed to load package client: could not load export data: no export data for \"github.com/goplugin/plugin-testing-framework/client\""
diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml
index b4059a8..c095a29 100644
--- a/.github/workflows/integration-tests-publish.yml
+++ b/.github/workflows/integration-tests-publish.yml
@@ -20,14 +20,16 @@ jobs:
steps:
- name: Collect Metrics
id: collect-gha-metrics
- uses: goplugin/push-gha-metrics-action@v1
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
- basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_CLOUD_HOST }}
+ id: starknet-e2e-publish
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Publish Integration Test Image
continue-on-error: true
- name: Checkout the repo
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Build Image
uses: ./.github/actions/build-test-image
with:
@@ -35,3 +37,12 @@ jobs:
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ - name: Notify Slack
+ # Only run this notification for merge to develop failures
+ if: failure() && github.event_name != 'workflow_dispatch'
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
+ env:
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
+ with:
+ channel-id: "#team-test-tooling-internal"
+ slack-message: ":x: :mild-panic-intensifies: Publish Integration Test Image failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}\nRepository: Starknet\n${{ format('Notifying ', secrets.GUARDIAN_SLACK_NOTIFICATION_HANDLE)}}"
diff --git a/.github/workflows/integration-tests-smoke.yml b/.github/workflows/integration-tests-smoke.yml
index ed2d64d..1569eb1 100644
--- a/.github/workflows/integration-tests-smoke.yml
+++ b/.github/workflows/integration-tests-smoke.yml
@@ -16,54 +16,80 @@ concurrency:
cancel-in-progress: true
env:
- PLUGIN_ENV_USER: ${{ github.actor }}
TEST_LOG_LEVEL: debug
CL_ECR: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin
ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin-starknet-tests:${{ github.sha }}
jobs:
- build_custom_plugin_image:
- name: Build Custom CL Image
+ build_plugin_image:
+ name: Build Plugin Image ${{matrix.image.name}}
runs-on: ubuntu-latest
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
environment: integration
permissions:
id-token: write
contents: read
+ strategy:
+ matrix:
+ image:
+ - name: ""
+ dockerfile: core/plugin.Dockerfile
+ tag-suffix: ""
+ - name: (plugins)
+ dockerfile: plugins/plugin.Dockerfile
+ tag-suffix: -plugins
steps:
- name: Collect Metrics
- if: always()
id: collect-gha-metrics
- uses: goplugin/push-gha-metrics-action@808c183d1f5c26a4f3fd50b75d3cf7b58d9aa293
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
- basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_CLOUD_HOST }}
- this-job-name: Build Custom CL Image
+ id: starknet-e2e-build${{ matrix.image.tag-suffix }}
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Build Plugin Image${{matrix.image.name}}
continue-on-error: true
- - name: Check if image exists
+ - name: Check if plugin-starknet image exists
id: check-image
- uses: goplugin/plugin-github-actions/docker/image-exists@8489879838862929f43f7d7cd1b33903965cf507 # v2.1.6
+ uses: goplugin/plugin-github-actions/docker/image-exists@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
repository: plugin
- tag: starknet.${{ github.sha }}
+ tag: starknet.${{ github.sha }}${{ matrix.image.tag-suffix }}
AWS_REGION: ${{ secrets.QA_AWS_REGION }}
AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- - name: Build Image
+ - name: Get core ref from PR body
+ if: steps.check-image.outputs.exists == 'false' && github.event_name == 'pull_request'
+ run: |
+ comment=$(gh pr view https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }} --json body -q '.body')
+ core_ref=$(echo $comment | grep -oP 'core ref: \K\S+' || true)
+ if [ ! -z "$core_ref" ]; then
+ echo "CUSTOM_CORE_REF=${core_ref}" >> "${GITHUB_ENV}"
+ else
+ echo "CUSTOM_CORE_REF=develop" >> "${GITHUB_ENV}"
+ fi
+ - name: Set core reference if workflow dispatch
+ if: steps.check-image.outputs.exists == 'false' && github.event_name == 'workflow_dispatch'
+ run: |
+ echo "CUSTOM_CORE_REF=${{ github.event.inputs.cl_branch_ref }}" >> "${GITHUB_ENV}"
+ - name: Build Image ${{ matrix.image.name }}
if: steps.check-image.outputs.exists == 'false'
- # note using a temporary commit for build-image that works around the go get issues, replace when go get issues are fixed please
- uses: goplugin/plugin-github-actions/plugin-testing-framework/build-image@a2bf54158aa0a77a55f432347bc9ecf8ef642c2b # cosmos_one_off
+ uses: goplugin/plugin-github-actions/plugin-testing-framework/build-image@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
cl_repo: goplugin/pluginv3.0
- cl_ref: ${{ github.event.inputs.cl_branch_ref }}
+ cl_ref: ${{ env.CUSTOM_CORE_REF }}
+ should_checkout: true
+ cl_dockerfile: ${{ matrix.image.dockerfile }}
# commit of the caller branch
dep_starknet_sha: ${{ github.event.pull_request.head.sha || github.sha }}
- push_tag: ${{ env.CL_ECR }}:starknet.${{ github.sha }}
+ push_tag: ${{ env.CL_ECR }}:starknet.${{ github.sha }}${{ matrix.image.tag-suffix }}
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_PRIVATE_GHA_PULL: ${{ secrets.QA_PRIVATE_GHA_PULL }}
- name: Print Plugin Image Built
run: |
echo "### plugin image tag used for this test run :link:" >> $GITHUB_STEP_SUMMARY
- echo "\`starknet.${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "\`starknet.${{ github.sha }}${{ matrix.image.tag-suffix }}\`" >> $GITHUB_STEP_SUMMARY
build_test_image:
environment: integration
@@ -75,14 +101,16 @@ jobs:
steps:
- name: Collect Metrics
id: collect-gha-metrics
- uses: goplugin/push-gha-metrics-action@v1
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
- basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_CLOUD_HOST }}
+ id: starknet-e2e-build-test-image
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Build Test Image
continue-on-error: true
- name: Checkout the repo
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: ${{ github.sha }}
- name: Build Image
@@ -93,17 +121,22 @@ jobs:
QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
run_tests:
- name: Run Smoke Tests
+ name: Run Smoke Tests ${{matrix.image.name}}
runs-on: ubuntu20.04-16cores-64GB
- needs: [ build_custom_plugin_image, build_test_image ]
+ needs: [ build_plugin_image, build_test_image ]
environment: integration
+ # these values need to match those used to build the plugin image
+ strategy:
+ matrix:
+ image:
+ - name: ""
+ tag-suffix: ""
+ test-name: embedded
+ - name: plugins
+ tag-suffix: -plugins
+ test-name: plugins
env:
- TEST_SUITE: smoke
- TEST_ARGS: -test.timeout 1h
- PRIVATE_KEY: ${{ secrets.GOERLI_PRIVATE_KEY }}
- ACCOUNT: ${{ secrets.GOERLI_ACCOUNT }}
- TTL: 1h
- NODE_COUNT: 5
+ INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com
permissions:
checks: write
pull-requests: write
@@ -111,27 +144,56 @@ jobs:
contents: read
steps:
- name: Collect Metrics
- if: always()
id: collect-gha-metrics
- uses: goplugin/push-gha-metrics-action@808c183d1f5c26a4f3fd50b75d3cf7b58d9aa293
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
- basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_CLOUD_HOST }}
- this-job-name: Run Smoke Tests
+ id: starknet-e2e-smoke${{ matrix.image.name }}
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Run Smoke Tests ${{ matrix.image.name }}
+ test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
continue-on-error: true
- name: Checkout the repo
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- - name: Run Tests
- uses: goplugin/plugin-github-actions/plugin-testing-framework/run-tests@8489879838862929f43f7d7cd1b33903965cf507 # v2.1.6
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+ - name: Build contracts
+ run: |
+ cd contracts && scarb --profile release build
+ - name: Build gauntlet
+ run: |
+ yarn install && yarn build
+ - name: Generate config overrides
+ run: | # https://github.com/goplugin/plugin-testing-framework/blob/main/config/README.md
+ cat << EOF > config.toml
+ [PluginImage]
+ image="${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin"
+ version="starknet.${{ github.sha }}${{ matrix.image.tag-suffix }}"
+ [Network]
+ selected_networks=["SIMULATED"]
+ [Common]
+ internal_docker_repo = "${{ env.INTERNAL_DOCKER_REPO }}"
+ stateful_db = false
+ EOF
+ # shellcheck disable=SC2002
+ BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0)
+ # shellcheck disable=SC2086
+ echo ::add-mask::$BASE64_CONFIG_OVERRIDE
+ # shellcheck disable=SC2086
+ echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV
+ - name: Run Tests ${{ matrix.image.name }}
+ uses: goplugin/plugin-github-actions/plugin-testing-framework/run-tests@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
- test_command_to_run: nix develop -c make test-integration-smoke-ci
+ aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ test_command_to_run: nix develop -c sh -c "make test=${{ matrix.image.test-name }} test-integration-smoke-ci"
test_download_vendor_packages_command: cd integration-tests && nix develop -c go mod download
cl_repo: ${{ env.CL_ECR }}
- cl_image_tag: starknet.${{ github.sha }}
+ cl_image_tag: starknet.${{ github.sha }}${{ matrix.image.tag-suffix }}
token: ${{ secrets.GITHUB_TOKEN }}
go_mod_path: ./integration-tests/go.mod
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
diff --git a/.github/workflows/integration-tests-soak.yml b/.github/workflows/integration-tests-soak.yml
index 37cefb3..d238b80 100644
--- a/.github/workflows/integration-tests-soak.yml
+++ b/.github/workflows/integration-tests-soak.yml
@@ -1,121 +1,83 @@
name: Integration Tests - Soak
-
on:
- push:
- branches:
- - main
- - develop
workflow_dispatch:
inputs:
- cl_branch_ref:
- description: Plugin repo branch to integrate with
+ base64_config:
+ description: Your .toml file as base64
required: true
- default: develop
- type: string
- l2_rpc_url:
- description: Override default RPC url which points to local devnet (Optional)
- required: false
- type: string
- node_count:
- description: Number of ocr nodes
+ cl_image_tag:
+ description: Core image tag
required: true
- default: 5
+ default: develop
type: string
- ttl:
- description: TTL for namespace
+ test_runner_tag:
+ description: Remote runner tag that will run the tests
+ default: develop
required: true
- default: 72h
type: string
-
-
-# Only run 1 of this workflow at a time per PR
-concurrency:
- group: integration-tests-starknet-${{ github.ref }}
- cancel-in-progress: true
-
env:
- ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin-starknet-tests:${{ github.sha }}
+ TEST_LOG_LEVEL: debug
+ CL_ECR: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin
+ ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin-starknet-tests:${{ inputs.test_runner_tag }}
jobs:
- build_custom_plugin_image:
- name: Build Custom CL Image
- runs-on: ubuntu-latest
- environment: integration
- permissions:
- id-token: write
- contents: read
- steps:
- - name: Check if image exists
- id: check-image
- uses: goplugin/plugin-github-actions/docker/image-exists@8489879838862929f43f7d7cd1b33903965cf507 # v2.1.6
- with:
- repository: plugin
- tag: starknet.${{ github.sha }}
- AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- - name: Build Image
- if: steps.check-image.outputs.exists == 'false'
- # note using a temporary commit for build-image that works around the go get issues, replace when go get issues are fixed please
- uses: goplugin/plugin-github-actions/plugin-testing-framework/build-image@a2bf54158aa0a77a55f432347bc9ecf8ef642c2b # cosmos_one_off
- with:
- cl_repo: goplugin/pluginv3.0
- # By default we are integrating with CL develop
- cl_ref: ${{ github.event.inputs.cl_branch_ref }}
- # commit of the caller branch
- dep_starknet_sha: ${{ github.event.pull_request.head.sha || github.sha }}
- push_tag: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin:starknet.${{ github.sha }}
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_PRIVATE_GHA_PULL: ${{ secrets.QA_PRIVATE_GHA_PULL }}
- - name: Print Plugin Image Built
- run: |
- echo "### plugin image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY
- echo "\`starknet.${{ github.sha }}\`" >>$GITHUB_STEP_SUMMARY
-
run_tests:
- name: Run Soak Tests
- runs-on: ubuntu-latest
- needs: [ build_custom_plugin_image ]
+ name: Run soak Tests
+ runs-on: ubuntu20.04-16cores-64GB
environment: integration
env:
- PLUGIN_ENV_USER: ${{ github.actor }}
- L2_RPC_URL: ${{ github.event.inputs.l2_rpc_url }}
- NODE_COUNT: ${{ github.event.inputs.node_count }}
- PRIVATE_KEY: ${{ secrets.GOERLI_PRIVATE_KEY }}
- ACCOUNT: ${{ secrets.GOERLI_ACCOUNT }}
- TTL: ${{ github.event.inputs.ttl }}
- DETACH_RUNNER: true
TEST_SUITE: soak
- TEST_ARGS: -test.timeout ${{ github.event.inputs.ttl }}
- TEST_LOG_LEVEL: debug
+ DETACH_RUNNER: true
+ INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com
permissions:
checks: write
pull-requests: write
id-token: write
contents: read
steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: starknet-e2e-soak
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Run soak Tests
+ test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
+ continue-on-error: true
- name: Checkout the repo
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- - name: Build Image
- uses: ./.github/actions/build-test-image
- with:
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+ - name: Build contracts
+ run: |
+ cd contracts && scarb --profile release build
+ - name: Build gauntlet
+ run: |
+ yarn install && yarn build
+ - name: Mask base64 config
+ # shellcheck disable=SC2086
+ run: |
+ BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64_config' "$GITHUB_EVENT_PATH")
+ echo "::add-mask::$BASE64_CONFIG_OVERRIDE"
+ echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> "$GITHUB_ENV"
- name: Run Tests
- uses: goplugin/plugin-github-actions/plugin-testing-framework/run-tests@ce87f8986ca18336cc5015df75916c2ec0a7c4b3 # v2.1.2
+ uses: goplugin/plugin-github-actions/plugin-testing-framework/run-tests@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
with:
- test_command_to_run: nix develop -c make test-integration-soak-ci
+ aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ test_command_to_run: cd ./integration-tests && go test -timeout 24h -count=1 -run TestOCRBasicSoak/embedded ./soak
test_download_vendor_packages_command: cd integration-tests && nix develop -c go mod download
- cl_repo: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/plugin
- cl_image_tag: starknet.${{ github.sha }}
+ cl_repo: ${{ env.CL_ECR }}
token: ${{ secrets.GITHUB_TOKEN }}
go_mod_path: ./integration-tests/go.mod
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ artifacts_location: /home/runner/work/plugin-starknet/plugin-starknet/integration-tests/soak/logs
+
diff --git a/.github/workflows/integration_contracts.yml b/.github/workflows/integration_contracts.yml
deleted file mode 100644
index f2c3690..0000000
--- a/.github/workflows/integration_contracts.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: Integration Contracts (Vendor, Examples)
-
-on:
- push:
- branches:
- - develop
- - main
- pull_request:
-
-jobs:
- integration_contracts_run_tests:
- name: Run Tests
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
- - name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
- with:
- nix_path: nixpkgs=channel:nixos-unstable
-
- - name: Test
- run: nix develop -c make test-integration-contracts
diff --git a/.github/workflows/integration_gauntlet.yml b/.github/workflows/integration_gauntlet.yml
index 4338e42..ba7cba2 100644
--- a/.github/workflows/integration_gauntlet.yml
+++ b/.github/workflows/integration_gauntlet.yml
@@ -8,17 +8,56 @@ on:
pull_request:
jobs:
+ gauntlet_eslint:
+ name: Gauntlet ESLint
+ env:
+ CI: true
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Install Nix
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+ extra_nix_config: "sandbox = false"
+ - name: Cache Nix
+ uses: cachix/cachix-action@v15
+ with:
+ name: plugin-cosmos
+ authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
+ - run: nix develop -c yarn install --frozen-lockfile
+ - run: nix develop -c yarn eslint
+ - name: Upload eslint report
+ if: always()
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ with:
+ name: gauntlet-eslint-report
+ path: ./eslint-report.json
+
integration_gauntlet_run_tests:
- name: Run Tests
+ name: Run Integration Gauntlet Tests
runs-on: ubuntu-latest
steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: starknet-integration-gauntlet
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Run Integration Gauntlet Tests
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+
- name: Test
run: nix develop -c make test-integration-gauntlet
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 018e273..f88be64 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -13,14 +13,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
+ - name: Install Cairo
+ uses: ./.github/actions/install-cairo
+
- name: Install
run: nix develop -c yarn install --frozen-lockfile
- - name: Check
- run: nix develop -c make format-check
+ # NOTE: Runs outside the nix environment because starknet-devnet still pulls in 0.x cairo which ends up taking precedence.
+ - name: Check Cairo
+ run: make format-cairo-check
+
+ - name: Check Typescript
+ run: nix develop -c make format-ts-check
diff --git a/.github/workflows/monitoring-build-push-ecr.yml b/.github/workflows/monitoring-build-push-ecr.yml
index fc10259..7f0becd 100644
--- a/.github/workflows/monitoring-build-push-ecr.yml
+++ b/.github/workflows/monitoring-build-push-ecr.yml
@@ -6,6 +6,7 @@ on:
- develop
paths:
- monitoring/**
+ - relayer/**
jobs:
build-and-publish-monitoring:
@@ -16,26 +17,26 @@ jobs:
contents: read
steps:
- name: Checkout repository
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1.7.0
+ uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
with:
role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }}
role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Login to ECR
- uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0
+ uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
with:
registry: ${{ secrets.MONITORING_ECR_HOSTNAME }}
- name: Setup Docker Buildx
- uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.2.1
+ uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
- name: Generate docker metadata
id: docker_meta
- uses: docker/metadata-action@57396166ad8aefe6098280995947635806a0e6ea # v4.1.1
+ uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
with:
flavor: | # prevent auto tagging with latest
latest=false
@@ -43,10 +44,10 @@ jobs:
tags: type=sha,format=long
- name: Build and push docker image
- uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 # v3.2.0
+ uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
with:
push: true
- context: monitoring
+ context: ./
file: monitoring/ops/Dockerfile
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
diff --git a/.github/workflows/relayer.yml b/.github/workflows/relayer.yml
index 0411fcd..42d1097 100644
--- a/.github/workflows/relayer.yml
+++ b/.github/workflows/relayer.yml
@@ -9,21 +9,69 @@ on:
jobs:
relayer_run_unit_tests:
- name: Run Unit Tests
+ name: Run Unit Tests ${{ matrix.test-type.name }}
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ test-type:
+ - name: test-unit-go
+ id: unit
+ - name: test-unit-go-race
+ id: race
+ - name: test-integration-go
+ id: integration
steps:
+ - name: Collect Metrics
+ if: matrix.test-type.id != 'race'
+ id: collect-gha-metrics
+ uses: goplugin/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: starknet-relay-unit-${{ matrix.test-type.id }}
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Run Unit Tests ${{ matrix.test-type.name }}
+ test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
- name: Checkout sources
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install Nix
- uses: cachix/install-nix-action@29bd9290ef037a3ecbdafe83cbd2185e9dd0fa0a # v20
+ uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Build
- run: nix develop -c make build-go-relayer
+ run: nix develop -c sh -c "make build-go-relayer"
- - name: Unit Test
- run: nix develop -c make test-unit-go
+ - name: Run ${{ matrix.test-type.name }}
+ run: nix develop -c sh -c "make ${{ matrix.test-type.name }} LOG_PATH=/tmp/gotest.log"
- - name: Integration Test
- run: nix develop -c make test-integration-go
+ - name: Upload Golangci relayer results
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: go-unit-tests-results-${{ matrix.test-type.id }}
+ path: |
+ /tmp/gotest.log
+ ./relayer/output.txt
+ ./relayer/coverage.txt
+ ./relayer/race_coverage.txt
+
+ check-tidy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ - name: Set up Go
+ uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
+ with:
+ go-version-file: "relayer/go.mod"
+ - name: Ensure "make gomodtidy" has been run
+ run: |
+ make gomodtidy
+ git diff --exit-code
+ - name: Ensure "make generate" has been run
+ run: |
+ make rm-mocked
+ make generate
+ git diff --stat --exit-code
diff --git a/.github/workflows/release/starknet-gauntlet-cli.yml b/.github/workflows/release/starknet-gauntlet-cli.yml
index f558acd..eda9b3d 100644
--- a/.github/workflows/release/starknet-gauntlet-cli.yml
+++ b/.github/workflows/release/starknet-gauntlet-cli.yml
@@ -24,7 +24,7 @@ jobs:
run: nix develop -c yarn bundle
# Store gauntlet-cli version
- name: Set Env Variables
- run: echo "STARKNET_GAUNTLET_CLI=$(npm info @pluginv3.0/starknet-gauntlet-cli version)" >> $GITHUB_ENV
+ run: echo "STARKNET_GAUNTLET_CLI=$(npm info @plugin/starknet-gauntlet-cli version)" >> $GITHUB_ENV
# Upload gauntlet binary to gauntlet-cli release
- name: Upload Gauntlet Binary
uses: svenstaro/upload-release-action@v2
@@ -33,5 +33,5 @@ jobs:
file: bin/plugin-starknet-*
file_glob: true
tag: |
- @pluginv3.0/starknet-gauntlet-cli@${{ env.STARKNET_GAUNTLET_CLI }}
+ @plugin/starknet-gauntlet-cli@${{ env.STARKNET_GAUNTLET_CLI }}
overwrite: false
diff --git a/.github/workflows/release/starknet-relayer.yml b/.github/workflows/release/starknet-relayer.yml
index 9607464..506203b 100644
--- a/.github/workflows/release/starknet-relayer.yml
+++ b/.github/workflows/release/starknet-relayer.yml
@@ -13,7 +13,7 @@ jobs:
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
# Store starknet version
- name: Set Env Variables
- run: echo "STARKNET_RELAYER=$(npm info @pluginv3.0/starknet-relayer version)" >> $GITHUB_ENV
+ run: echo "STARKNET_RELAYER=$(npm info @plugin/starknet-relayer version)" >> $GITHUB_ENV
# Check if release tag exists
- name: Check release tag
uses: mukunku/tag-exists-action@5dfe2bf779fe5259360bb10b2041676713dcc8a3 # v1.1.0
diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml
new file mode 100644
index 0000000..7878af2
--- /dev/null
+++ b/.github/workflows/sonar-scan.yml
@@ -0,0 +1,110 @@
+name: SonarQube Scan
+
+on:
+ pull_request:
+
+jobs:
+ wait_for_workflows:
+ name: Wait for workflows
+ runs-on: ubuntu-latest
+ if: always()
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
+
+ - name: Wait for Workflows
+ id: wait
+ uses: goplugin/plugin-github-actions/utils/wait-for-workflows@main
+ with:
+ max-timeout: "1200"
+ polling-interval: "30"
+ exclude-workflow-names: "Amarna Analysis,Changesets,Integration Contracts (Vendor, Examples),Integration Tests Publish,Integration Tests - Smoke,Integration Tests - Soak,Build and push on-chain monitor image to ECR,Contracts,Lint"
+ exclude-workflow-ids: ""
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ env:
+ DEBUG: "true"
+
+ sonarqube:
+ name: SonarQube Scan
+ needs: [ wait_for_workflows ]
+ runs-on: ubuntu-latest
+ if: always()
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # fetches all history for all tags and branches to provide more metadata for sonar reports
+
+ - name: Download Golangci unit tests reports
+ uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
+ with:
+ workflow: relayer.yml
+ workflow_conclusion: ""
+ name_is_regexp: true
+ name: go-unit-tests-results
+ if_no_artifact_found: warn
+
+ - name: Download Golangci Relayer report
+ uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
+ with:
+ workflow: golangci-lint.yml
+ workflow_conclusion: ""
+ name_is_regexp: true
+ name: golangci-lint-relayer-report
+ if_no_artifact_found: warn
+
+ - name: Download Golangcio Ops report
+ uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
+ with:
+ workflow: golangci-lint.yml
+ workflow_conclusion: ""
+ name_is_regexp: true
+ name: golangci-lint-ops-report
+ if_no_artifact_found: warn
+
+ - name: Download Golangci-lint Integration tests report
+ uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
+ with:
+ workflow: golangci-lint.yml
+ workflow_conclusion: ""
+ name_is_regexp: true
+ name: golangci-lint-integration-tests-report
+ if_no_artifact_found: warn
+
+ - name: Download gauntlet eslint reports
+ uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 # v6
+ with:
+ workflow: integration_gauntlet.yml
+ workflow_conclusion: ""
+ name_is_regexp: true
+ name: gauntlet-eslint-report
+ if_no_artifact_found: warn
+
+ - name: Set SonarQube Report Paths
+ id: sonarqube_report_paths
+ shell: bash
+ run: |
+ {
+ echo "sonarqube_tests_report_paths=$(find . -type f -name output.txt | paste -sd "," -)"
+ echo "sonarqube_coverage_report_paths=$(find . -type f -name '*coverage.txt' | paste -sd "," -)"
+ echo "sonarqube_golangci_report_paths=$(find . -type f -name 'golangci-*-report.xml' -printf "%p,")"
+ echo "sonarqube_eslint_report_paths=$(find -type f -name 'eslint-report.json' -printf "%p")" >> $GITHUB_OUTPUT
+ } >> "$GITHUB_OUTPUT"
+
+ - name: Update ESLint report symlinks
+ continue-on-error: true
+ run: sed -i 's+/home/runner/work/feeds-manager/feeds-manager/+/github/workspace/+g' ${{ steps.sonarqube_report_paths.outputs.sonarqube_eslint_report_paths }}
+
+ - name: SonarQube Scan
+ uses: sonarsource/sonarqube-scan-action@86fe81775628f1c6349c28baab87881a2170f495 # v2.1.0
+ with:
+ args: >
+ -Dsonar.go.tests.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_tests_report_paths }}
+ -Dsonar.go.coverage.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_coverage_report_paths }}
+ -Dsonar.go.golangci-lint.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_golangci_report_paths }}
+ -Dsonar.eslint.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_eslint_report_paths }}
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
diff --git a/.gitignore b/.gitignore
index fe4e630..bf22810 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
+.snfoundry_cache
.direnv
artifacts/
+vendor/
accounts.json
node.json
package-lock.json
@@ -13,8 +15,6 @@ bin
.DS_Store
.temp/
-coverage/
-coverage.json
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -59,11 +59,13 @@ pip-delete-this-directory.txt
htmlcov/
.tox/
.nox/
-.coverage
-.coverage.*
+*report.xml
+*report.json
+*.out
+*coverage*
+testdata/
.cache
nosetests.xml
-coverage.xml
*.cover
*.py,cover
.hypothesis/
@@ -162,3 +164,7 @@ integration-tests/smoke/logs
integration-tests/soak/logs
remote.test
ztarrepo.tar.gz
+eslint-report.json
+.run.id
+.local-mock-server
+override*.toml
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..82a63fc
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,7 @@
+[submodule "vendor/cairo"]
+ path = vendor/cairo
+ url = https://github.com/starkware-libs/cairo
+[submodule "vendor/scarb"]
+ path = vendor/scarb
+ url = https://github.com/software-mansion/scarb
+ ignore = dirty
diff --git a/.golangci.yml b/.golangci.yml
index 6de791b..c3b2f81 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -5,11 +5,20 @@ linters:
- exhaustive
- exportloopref
- revive
- # - goimports
+ - goimports
- gosec
- misspell
- # - rowserrcheck
+ - rowserrcheck
- errorlint
+ - unconvert
+ - sqlclosecheck
+ - noctx
+ - whitespace
+ - depguard
+ - containedctx
+ - fatcontext
+ - mirror
+ - loggercheck
linters-settings:
exhaustive:
default-signifies-exhaustive: true
@@ -25,8 +34,21 @@ linters-settings:
# - G304
# - G404
govet:
- # report about shadowed variables
- check-shadowing: true
+ enable:
+ - shadow
+ settings:
+ printf:
+ # Additionally check custom logger
+ funcs:
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Debugf
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Infof
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Warnf
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Errorf
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Panicf
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Fatalf
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).AssumptionViolationf
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).Tracef
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).Criticalf
errorlint:
# Allow formatting of errors without %w
errorf: false
@@ -40,9 +62,10 @@ linters-settings:
- name: error-return
- name: error-strings
- name: error-naming
+ - name: exported
- name: if-return
- name: increment-decrement
- # - name: var-naming
+ - name: var-naming
- name: var-declaration
- name: package-comments
- name: range
@@ -61,23 +84,67 @@ linters-settings:
- name: struct-tag
# - name: string-format
- name: string-of-int
- # - name: range-val-address
+ - name: range-val-address
- name: range-val-in-closure
- name: modifies-value-receiver
- name: modifies-parameter
- name: identical-branches
- name: get-return
# - name: flag-parameter
- # - name: early-return
+ - name: early-return
- name: defer
- name: constant-logical-expr
# - name: confusing-naming
# - name: confusing-results
- name: bool-literal-in-expr
- name: atomic
+ depguard:
+ rules:
+ main:
+ list-mode: lax
+ deny:
+ - pkg: "cosmossdk.io/errors"
+ desc: Use the standard library instead
+ - pkg: "github.com/go-gorm/gorm"
+ desc: Use github.com/jmoiron/sqlx directly instead
+ - pkg: "github.com/gofrs/uuid"
+ desc: Use github.com/google/uuid instead
+ - pkg: "github.com/pkg/errors"
+ desc: Use the standard library instead, for example https://pkg.go.dev/errors#Join
+ - pkg: "github.com/satori/go.uuid"
+ desc: Use github.com/google/uuid instead
+ - pkg: "github.com/test-go/testify/assert"
+ desc: Use github.com/stretchr/testify/assert instead
+ - pkg: "github.com/test-go/testify/mock"
+ desc: Use github.com/stretchr/testify/mock instead
+ - pkg: "github.com/test-go/testify/require"
+ desc: Use github.com/stretchr/testify/require instead
+ - pkg: "go.uber.org/multierr"
+ desc: Use the standard library instead, for example https://pkg.go.dev/errors#Join
+ - pkg: "gopkg.in/guregu/null.v1"
+ desc: Use gopkg.in/guregu/null.v4 instead
+ - pkg: "gopkg.in/guregu/null.v2"
+ desc: Use gopkg.in/guregu/null.v4 instead
+ - pkg: "gopkg.in/guregu/null.v3"
+ desc: Use gopkg.in/guregu/null.v4 instead
+ - pkg: github.com/go-gorm/gorm
+ desc: Use github.com/jmoiron/sqlx directly instead
+ loggercheck:
+ # Check that *w logging functions have even number of args (i.e., well formed key-value pairs).
+ rules:
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Debugw
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Infow
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Warnw
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Errorw
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Panicw
+ - (github.com/goplugin/plugin-common/pkg/logger.Logger).Fatalw
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).AssumptionViolationw
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).Tracew
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).Criticalw
+ - (github.com/goplugin/plugin-common/pkg/logger.SugaredLogger).With
issues:
exclude-rules:
- path: test
text: "^G404:"
linters:
- - gosec
+ - gosec
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
index f104393..2e47077 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -8,6 +8,7 @@ dist
*.yml
typechain-types
*.html
+*.md
# Vendor files (contracts)
vendor
diff --git a/.tool-versions b/.tool-versions
index 8d6eb77..e3f251c 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,14 +1,17 @@
# Languages
nodejs 18.6.0
yarn 1.22.19
-golang 1.20.1
+golang 1.21.5
python 3.9.13
# Tools
-mockery 2.13.0-beta.1
-golangci-lint 1.51.2
+mockery 2.22.1
+golangci-lint 1.55.0
actionlint 1.6.12
shellcheck 0.8.0
+scarb 2.6.5
+postgres 15.1
+starknet-foundry 0.27.0
# Kubernetes
k3d 5.4.4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0af93a2..c738e78 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,15 +4,15 @@ This repository adheres to [Semantic Versioning](http://semver.org/).
Plugin-Starknet contains a number of projects, all individually versioned and released. Please consult the following changelogs for more information:
-- [@pluginv3.0/starknet-relayer](/relayer/)
-- [@pluginv3.0/starknet-gauntlet](/packages-ts/starknet-gauntlet/)
-- [@pluginv3.0/starknet-gauntlet-cli](/packages-ts/starknet-gauntlet-cli/)
-- [@pluginv3.0/starknet-gauntlet-ocr2](/packages-ts/starknet-gauntlet-ocr2/)
-- [@pluginv3.0/starknet-gauntlet-oz](/packages-ts/starknet-gauntlet-oz/)
-- [@pluginv3.0/starknet-gauntlet-argent](/packages-ts/starknet-gauntlet-argent/)
-- [@pluginv3.0/starknet-gauntlet-token](/packages-ts/starknet-gauntlet-token/)
-- [@pluginv3.0/starknet-contracts](/contracts/)
-- [@pluginv3.0/starknet-integration-tests](/integration-tests/)
+- [@plugin/starknet-relayer](/relayer/)
+- [@plugin/starknet-gauntlet](/packages-ts/starknet-gauntlet/)
+- [@plugin/starknet-gauntlet-cli](/packages-ts/starknet-gauntlet-cli/)
+- [@plugin/starknet-gauntlet-ocr2](/packages-ts/starknet-gauntlet-ocr2/)
+- [@plugin/starknet-gauntlet-oz](/packages-ts/starknet-gauntlet-oz/)
+- [@plugin/starknet-gauntlet-argent](/packages-ts/starknet-gauntlet-argent/)
+- [@plugin/starknet-gauntlet-token](/packages-ts/starknet-gauntlet-token/)
+- [@plugin/starknet-contracts](/contracts/)
+- [@plugin/starknet-integration-tests](/integration-tests/)
If a project is pre-v1.0, minor version bumps may cause breaking changes. All breaking changes are noted in changelogs.
diff --git a/Makefile b/Makefile
index 6609f76..367c965 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-BIN_DIR = bin
+BIN_DIR = $(abspath bin)
export GOPATH ?= $(shell go env GOPATH)
export GO111MODULE ?= on
@@ -80,8 +80,9 @@ build-go-ops:
build-go-integration-tests:
cd integration-tests/ && go build ./...
+# TODO: fix and readd build-ts-examples
.PHONY: build-ts
-build-ts: build-ts-workspace build-ts-contracts build-ts-examples
+build-ts: build-ts-workspace build-cairo-contracts build-sol-contracts
.PHONY: build-ts-workspace
build-ts-workspace:
@@ -90,17 +91,18 @@ build-ts-workspace:
# TODO: use yarn workspaces features instead of managing separately like this
# https://yarnpkg.com/cli/workspaces/foreach
-.PHONY: build-ts-contracts
-build-ts-contracts:
+.PHONY: build-sol-contracts
+build-sol-contracts:
cd contracts/ && \
yarn install --frozen-lockfile && \
- yarn compile
+ yarn compile:solidity
+# TODO: this should build cairo contracts when they are rewritten
.PHONY: build-ts-examples
build-ts-examples:
cd examples/contracts/aggregator-consumer && \
yarn install --frozen-lockfile && \
- yarn compile
+ yarn compile:solidity
.PHONY: gowork
gowork:
@@ -120,7 +122,7 @@ format: format-go format-cairo format-ts
format-check: format-cairo-check format-ts-check
.PHONY: format-go
-format-go: format-go-fmt format-go-mod-tidy
+format-go: format-go-fmt gomodtidy
.PHONY: format-go-fmt
format-go-fmt:
@@ -128,26 +130,35 @@ format-go-fmt:
cd ./ops && go fmt ./...
cd ./integration-tests && go fmt ./...
-.PHONY: format-go-mod-tidy
-format-go-mod-tidy:
- cd ./relayer && go mod tidy
- cd ./monitoring && go mod tidy
- cd ./ops && go mod tidy
- cd ./integration-tests && go mod tidy
+.PHONY: gomods
+gomods: ## Install gomods
+ go install github.com/jmank88/gomods@v0.1.3
+
+.PHONY: gomodtidy
+gomodtidy: gomods
+ gomods tidy
+
+.PHONY: mockery
+mockery: $(mockery) ## Install mockery.
+ go install github.com/vektra/mockery/v2@v2.43.2
+
+.PHONY: rm-mocked
+rm-mocked:
+ grep -rl "^// Code generated by mockery" | grep .go$ | xargs -r rm
+
+.PHONY: generate
+generate: mockery gomods
+ gomods -w go generate -x ./...
.PHONY: format-cairo
format-cairo:
- find ./contracts/src -name "*.cairo" -type f \
- -exec cairo-format -i --one_item_per_line {} +
- find ./examples -name "*.cairo" -type f \
- -exec cairo-format -i --one_item_per_line {} +
+ cairo-format -i ./contracts/src/**/*.cairo
+ cairo-format -i ./examples/**/*.cairo
.PHONY: format-cairo-check
format-cairo-check:
- find ./contracts/src -name "*.cairo" -type f \
- -exec cairo-format -c --one_item_per_line {} +
- find ./examples -name "*.cairo" -type f \
- -exec cairo-format -c --one_item_per_line {} +
+ cairo-format -c ./contracts/src/**/*.cairo
+ cairo-format -c ./examples/**/*.cairo
.PHONY: format-ts
format-ts:
@@ -159,37 +170,39 @@ format-ts-check:
.PHONY: lint-go-ops
lint-go-ops:
- cd ./ops && golangci-lint --color=always run
+ cd ./ops && golangci-lint --color=always --out-format checkstyle:golangci-lint-ops-report.xml run
.PHONY: lint-go-relayer
lint-go-relayer:
- cd ./relayer && golangci-lint --color=always run
+ cd ./relayer && golangci-lint --color=always --out-format checkstyle:golangci-lint-relayer-report.xml run
.PHONY: lint-go-test
lint-go-test:
- cd ./integration-tests && golangci-lint --color=always --exclude=dot-imports run
+ cd ./integration-tests && golangci-lint --color=always --exclude=dot-imports --out-format checkstyle:golangci-lint-integration-tests-report.xml run
.PHONY: test-go
-test-go: test-unit-go test-integration-go
+test-go: test-unit-go test-unit-go-race test-integration-go
.PHONY: test-unit
-test-unit: test-unit-go
+test-unit: test-unit-go test-unit-go-race
+LOG_PATH ?= ./gotest.log
.PHONY: test-unit-go
test-unit-go:
- cd ./relayer && go test -v ./...
- cd ./relayer && go test -v ./... -race -count=10
+ cd ./relayer && go test -json ./... -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt 2>&1 | tee $(LOG_PATH) | gotestloghelper -ci
+
+.PHONY: test-unit-go-race
+test-unit-go-race:
+ cd ./relayer && CGO_ENABLED=1 go test -v ./... -race -count=10 -coverpkg=./... -coverprofile=race_coverage.txt
.PHONY: test-integration-go
# only runs tests with TestIntegration_* + //go:build integration
-test-integration-go:
- cd ./relayer && go test -v ./... -run TestIntegration -tags integration
+test-integration-go: env-devnet-hardhat
+ cd ./relayer && go test -json ./... -run TestIntegration -tags integration 2>&1 | tee $(LOG_PATH) | gotestloghelper -ci
.PHONY: test-integration-prep
test-integration-prep:
- python -m venv ~/cairo_venv && \
- . ~/cairo_venv/bin/activate
- cd ./contracts && pip install -r requirements.txt
+ cd ./contracts
make build
.PHONY: test-integration
@@ -204,40 +217,35 @@ test-integration-smoke: test-integration-prep
.PHONY: test-integration-smoke-ci
test-integration-smoke-ci:
cd integration-tests/ && \
- go test --timeout=2h -v -count=1 -json ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt
+ go test --timeout=2h -v -count=1 -run TestOCRBasic/$(test) -json ./smoke | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage
.PHONY: test-integration-soak
test-integration-soak: test-integration-prep
cd integration-tests/ && \
- go test --timeout=1h -v ./soak
+ go test --timeout=1h -v -json ./soak
# CI Already has already ran test-integration-prep
.PHONY: test-integration-soak-ci
test-integration-soak-ci:
cd integration-tests/ && \
- go test --timeout=1h -v -count=1 -json ./soak 2>&1 | tee /tmp/gotest.log | gotestfmt
+ go test --timeout=1h -v -count=1 -json ./soak
-.PHONY: test-integration-contracts
-# TODO: better network lifecycle setup - requires external network (L1 + L2)
-test-integration-contracts: build-ts env-devnet-hardhat
- cd examples/contracts/aggregator-consumer/ && \
- yarn test
- cd packages-ts/integration-eqlabs-multisig/ && \
- yarn test
- cd packages-ts/starknet/ && \
- yarn test
+.PHONY: test-examples
+test-examples:
+ cd ./examples/contracts/aggregator_consumer && \
+ snforge test
.PHONY: test-integration-gauntlet
-# TODO: better network lifecycle setup - tests setup/run their own network (L1 + conflict w/ above if not cleaned up)
-test-integration-gauntlet: build-ts env-devnet-hardhat-down
+# TODO: fix example
+# cd packages-ts/starknet-gauntlet-example/ && \
+# yarn test
+test-integration-gauntlet: build-ts env-devnet-hardhat
cd packages-ts/starknet-gauntlet/ && \
yarn test
cd packages-ts/starknet-gauntlet-argent/ && \
yarn test
cd packages-ts/starknet-gauntlet-cli/ && \
yarn test
- cd packages-ts/starknet-gauntlet-example/ && \
- yarn test
cd packages-ts/starknet-gauntlet-multisig/ && \
yarn test
cd packages-ts/starknet-gauntlet-ocr2/ && \
@@ -253,10 +261,18 @@ test-integration-gauntlet: build-ts env-devnet-hardhat-down
test-ts: test-ts-contracts test-integration-contracts test-integration-gauntlet
.PHONY: test-ts-contracts
-test-ts-contracts: build-ts-contracts build-ts-workspace env-devnet-hardhat
+test-ts-contracts: build-ts env-devnet-hardhat
cd contracts/ && \
yarn test
+.PHONY: build-cairo-contracts
+build-cairo-contracts:
+ cd contracts && scarb --profile release build
+
+.PHONY: test-cairo-contracts
+test-cairo-contracts:
+ cd contracts && scarb test
+
# TODO: this script needs to be replaced with a predefined K8s enviroment
.PHONY: env-devnet-hardhat
env-devnet-hardhat:
diff --git a/check.sh b/check.sh
new file mode 100755
index 0000000..e53d098
--- /dev/null
+++ b/check.sh
@@ -0,0 +1,32 @@
+find . -name "go.mod"|xargs egrep -irn 'goplugin/wasp'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/push-gha-metrics-action'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/qa-charts'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/pluginv3.0-env'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-env'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/asdf-helmenv'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/helmenv'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/external-adapters-js'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/dummy-external-adapter'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-vrf'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/n/gencodec'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-github-actions'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/ccip'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/tool-versions-to-env-action'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/qa-charts'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-solhint-rules'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-staknet'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/chain-selectors'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-automation'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-ccip'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-common'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-cosmos'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-data-streams'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-testing-framework'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-feeds'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-protos'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-solana'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/plugin-libocr'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/tdh2'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/wsrpc'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/grpc-proxy'
+find . -name "go.mod"|xargs egrep -irn 'goplugin/go-plugin'
diff --git a/contracts/.gitattributes b/contracts/.gitattributes
new file mode 100644
index 0000000..0792ac6
--- /dev/null
+++ b/contracts/.gitattributes
@@ -0,0 +1 @@
+*.cairo linguist-language=rust
\ No newline at end of file
diff --git a/contracts/.gitignore b/contracts/.gitignore
index 3446f76..0cca96d 100644
--- a/contracts/.gitignore
+++ b/contracts/.gitignore
@@ -1,3 +1,4 @@
starknet-artifacts/
cache/
-typechain-types/
+target/
+node_modules/
diff --git a/contracts/.helix/languages.toml b/contracts/.helix/languages.toml
deleted file mode 100644
index 70f2df9..0000000
--- a/contracts/.helix/languages.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-[[language]]
-name = "cairo"
-language-server = { command = "node", args = ["node_modules/cairo-ls/out/server.js", "--stdio"] }
-[language.config]
-cairols = { venvCommand = ". .venv/bin/activate", sourceDir = "contracts" }
diff --git a/contracts/README.md b/contracts/README.md
new file mode 100644
index 0000000..6a3a810
--- /dev/null
+++ b/contracts/README.md
@@ -0,0 +1,141 @@
+# Minimal Cairo 1.0 Template ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/auditless/cairo-template/blob/main/LICENSE)
+
+[Built with **`auditless/cairo-template`**](https://github.com/auditless/cairo-template)
+
+A minimal template for building smart contracts with Cairo 1.0
+using the [Quaireaux](https://github.com/keep-starknet-strange/quaireaux) project defaults.
+
+## How it works
+
+- No submodules, forks or other heavy machinery
+- Uses the [`cairo-test-runner`](https://github.com/starkware-libs/cairo/blob/main/crates/cairo-lang-test-runner/README.md) binary for running tests
+- Built as a [Scarb](https://github.com/software-mansion/scarb) package for reusability and uses Scarb dependencies for libraries
+- Has reproducible builds using GitHub Actions
+- Uses Scarb scripts natively for custom commands
+- Includes advanced debugging views like the Sierra intermediate representation
+
+## Installing dependencies
+
+### Step 1: Install Cairo 1.0 (guide by [Abdel](https://github.com/abdelhamidbakhta))
+
+If you are on an x86 Linux system and able to use the release binary,
+you can download Cairo here https://github.com/starkware-libs/cairo/releases.
+
+For everyone, else, we recommend compiling Cairo from source like so:
+
+```bash
+# Install stable Rust
+$ rustup override set stable && rustup update
+
+# Clone the Cairo compiler in $HOME/Bin
+$ cd ~/Bin && git clone git@github.com:starkware-libs/cairo.git && cd cairo
+
+# Generate release binaries
+$ cargo build --all --release
+```
+
+**NOTE: Keeping Cairo up to date**
+
+Now that your Cairo compiler is in a cloned repository, all you will need to do
+is pull the latest changes and rebuild as follows:
+
+```bash
+$ cd ~/Bin/cairo && git fetch && git pull && cargo build --all --release
+```
+
+### Step 2: Add Cairo 1.0 executables to your path
+
+```bash
+export PATH="$HOME/Bin/cairo/target/release:$PATH"
+```
+
+**NOTE: If installing from a Linux binary, adapt the destination path accordingly.**
+
+This will make available several binaries. The one we use is called `cairo-test`.
+
+### Step 3: Install the Cairo package manager Scarb
+
+Follow the installation guide in [Scarb's Repository](https://github.com/software-mansion/scarb).
+
+### Step 4: Setup Language Server
+
+#### VS Code Extension
+
+- Disable previous Cairo 0.x extension
+- Install the Cairo 1 extension for proper syntax highlighting and code navigation.
+Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md).
+
+#### Cairo Language Server
+
+From [Step 1](#step-1-install-cairo-10-guide-by-abdel), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard.
+
+```bash
+$ which cairo-language-server | pbcopy
+```
+
+Update the `languageServerPath` of the Cairo 1.0 extension by pasting the path.
+
+## How to use this template
+
+First you will need to clone the repository or click the `Use this template` button
+at the top of the page to create a new repository based on the template.
+
+Next, you will want to update the configuration files with the name of your project:
+
+```
+├── .cairo_project.toml
+└── .Scarb.toml
+```
+
+## Working with your project
+
+The Cairo template currently supports building and testing contracts.
+
+### Build
+
+Build the contracts.
+
+```bash
+$ scarb build
+```
+
+### Test
+
+Run the tests in `src/test`:
+
+```bash
+$ scarb run test
+```
+
+### Format
+
+Format the Cairo source code (using Scarb):
+
+```bash
+$ scarb fmt
+```
+
+### Sierra (advanced)
+
+View the compiled Sierra output of your Cairo code:
+
+```bash
+$ scarb run sierra
+```
+
+## Thanks to
+
+- The [Quaireaux](https://github.com/keep-starknet-strange/quaireaux) team for coming up with
+this configuration and especially [Abdel](https://github.com/abdelhamidbakhta) for helping me with Cairo 1.0 installation
+- [Paul Berg](https://github.com/PaulRBerg) and the [foundry-template](https://github.com/paulrberg/foundry-template) project which served as inspiration
+- Last but not least, the StarkWare team for building the first smart contract language that is a joy to use
+
+## Other templates
+
+- [ArgentX template](https://github.com/argentlabs/starknet-build/tree/main/cairo1.0) is built as a fork of the compiler
+- [Eni's cairo1-template](https://github.com/msaug/cairo1-template) uses git submodules for installation
+- [Shramee's Starklings](https://github.com/shramee/starklings-cairo1) use the cairo1 crates as libraries and builds its own framework
+
+## License
+
+[MIT](https://github.com/auditless/cairo-template/blob/main/LICENSE) © [Auditless Limited](https://www.auditless.com)
diff --git a/contracts/Scarb.lock b/contracts/Scarb.lock
new file mode 100644
index 0000000..a182a62
--- /dev/null
+++ b/contracts/Scarb.lock
@@ -0,0 +1,74 @@
+# Code generated by scarb DO NOT EDIT.
+version = 1
+
+[[package]]
+name = "alexandria_bytes"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+ "alexandria_math",
+]
+
+[[package]]
+name = "alexandria_data_structures"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_encoding",
+]
+
+[[package]]
+name = "alexandria_encoding"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_bytes",
+ "alexandria_math",
+ "alexandria_numeric",
+]
+
+[[package]]
+name = "alexandria_math"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+]
+
+[[package]]
+name = "alexandria_numeric"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_math",
+ "alexandria_searching",
+]
+
+[[package]]
+name = "alexandria_searching"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+]
+
+[[package]]
+name = "plugin"
+version = "0.1.0"
+dependencies = [
+ "alexandria_bytes",
+ "alexandria_encoding",
+ "openzeppelin",
+ "snforge_std",
+]
+
+[[package]]
+name = "openzeppelin"
+version = "0.10.0"
+source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.10.0#d77082732daab2690ba50742ea41080eb23299d3"
+
+[[package]]
+name = "snforge_std"
+version = "0.27.0"
+source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.27.0#2d99b7c00678ef0363881ee0273550c44a9263de"
diff --git a/contracts/Scarb.toml b/contracts/Scarb.toml
new file mode 100644
index 0000000..3c13d0b
--- /dev/null
+++ b/contracts/Scarb.toml
@@ -0,0 +1,34 @@
+[package]
+name = "plugin"
+version = "0.1.0"
+cairo-version = "2.6.3"
+description = "Plugin contracts for Starknet"
+homepage = "https://github.com/goplugin/plugin-starknet"
+
+[scripts]
+sierra = "cairo-compile . -r"
+test = "snforge test"
+# Add your own custom commands and run them with scarb run
+
+# Uncomment if you want to use dependencies
+# Note: currently testing doesn't work with dependencies
+[dependencies]
+starknet = ">=2.6.3"
+openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.10.0" }
+alexandria_bytes = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "bcdca70afdf59c9976148e95cebad5cf63d75a7f" }
+alexandria_encoding = { git = "https://github.com/keep-starknet-strange/alexandria.git", rev = "bcdca70afdf59c9976148e95cebad5cf63d75a7f" }
+snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.27.0" }
+
+[lib]
+
+[[target.starknet-contract]]
+sierra = true
+casm = true
+# pythonic hints are necessary for cairo-lang to parse the casm file:
+# Unsupported compiled class format. Cairo 1.0 compiled class must contain the attribute `pythonic_hints`.
+casm-add-pythonic-hints = true
+
+# this elevates the severity of disallowed libfuncs to compilation errors
+# https://docs.swmansion.com/scarb/docs/starknet/contract-target#allowed-libfuncs-validation
+allowed-libfuncs-deny = true
+allowed-libfuncs-list.name = "audited"
diff --git a/contracts/cairo_project.toml b/contracts/cairo_project.toml
new file mode 100644
index 0000000..9b15402
--- /dev/null
+++ b/contracts/cairo_project.toml
@@ -0,0 +1,2 @@
+[crate_roots]
+plugin = "src"
diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts
index 339dcc6..391b134 100644
--- a/contracts/hardhat.config.ts
+++ b/contracts/hardhat.config.ts
@@ -1,8 +1,8 @@
import { HardhatUserConfig } from 'hardhat/types'
-import '@shardlabs/starknet-hardhat-plugin'
import '@nomiclabs/hardhat-ethers'
import '@nomicfoundation/hardhat-chai-matchers'
import 'solidity-coverage'
+import { prepareHardhatArtifacts } from './test/setup'
const COMPILER_SETTINGS = {
optimizer: {
@@ -18,53 +18,37 @@ const COMPILER_SETTINGS = {
* @type import('hardhat/config').HardhatUserConfig
*/
const config: HardhatUserConfig = {
+ // NOTE: hardhat comes with a special built-in network called 'harhdat'. This network is automatically created and
+ // used if no networks are defined in our config: https://hardhat.org/hardhat-runner/docs/config#hardhat-network. It
+ // is important to note that we DO NOT want to use this network. Our testing scripts already spawn a hardhat node in
+ // a container, so we should use this for the l1 <> l2 messaging tests rather than the auto-generated one from hardhat.
+ // To achieve this, the 'defaultNetwork' and 'networks' properties have been adjusted such that they reference the
+ // containerized hardhat node.
+ defaultNetwork: 'localhost',
+ networks: {
+ localhost: {
+ url: 'http://127.0.0.1:8545',
+ },
+ },
solidity: {
compilers: [
- {
- version: '0.6.12',
- settings: COMPILER_SETTINGS,
- },
{
version: '0.8.15',
settings: COMPILER_SETTINGS,
},
],
},
- starknet: {
- // dockerizedVersion: "0.10.0", // alternatively choose one of the two venv options below
- // uses (my-venv) defined by `python -m venv path/to/my-venv`
- // venv: "../.venv",
-
- // uses the currently active Python environment (hopefully with available Starknet commands!)
- venv: 'active',
- // network: "alpha",
- network: 'devnet',
- wallets: {
- OpenZeppelin: {
- accountName: 'OpenZeppelin',
- modulePath: 'starkware.starknet.wallets.open_zeppelin.OpenZeppelinAccount',
- accountPath: '~/.starknet_accounts',
- },
- },
- },
- networks: {
- devnet: {
- url: 'http://127.0.0.1:5050',
- },
- integratedDevnet: {
- url: 'http://127.0.0.1:5050',
- venv: 'active',
- args: ['--lite-mode'],
- // dockerizedVersion: "0.2.0"
- },
- },
mocha: {
timeout: 10000000,
+ rootHooks: {
+ beforeAll: prepareHardhatArtifacts,
+ },
},
paths: {
- sources: './src',
+ sources: './solidity',
starknetSources: './src',
- cairoPaths: ['./vendor/starkware-libs/starkgate-contracts/src'],
+ starknetArtifacts: './target/release',
+ cairoPaths: [],
},
}
diff --git a/contracts/package.json b/contracts/package.json
index 5c340ea..ed19729 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -1,13 +1,11 @@
{
- "name": "@pluginv3.0/starknet-contracts",
+ "name": "@plugin/starknet-contracts",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
- "compile:cairo": "hardhat starknet-compile",
"compile:solidity": "hardhat compile",
- "compile": "yarn compile:cairo && yarn compile:solidity",
- "test": "hardhat --network localhost test"
+ "test": "hardhat test"
},
"author": "",
"license": "MIT",
@@ -15,18 +13,16 @@
"@ethereum-waffle/mock-contract": "^4.0.4",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.3",
"@nomiclabs/hardhat-ethers": "^2.0.5",
- "@shardlabs/starknet-hardhat-plugin": "^0.8.0-alpha.0",
"@types/chai": "^4.3.3",
"@types/elliptic": "^6.4.14",
"@types/mocha": "^9.1.1",
"chai": "^4.3.6",
"ethers": "^5.6.8",
- "hardhat": "^2.10.2",
+ "hardhat": "^2.16.1",
"solidity-coverage": "^0.8.2"
},
"dependencies": {
- "@pluginv3.0/contracts": "^0.4.2",
- "@pluginv3.0/starknet": "^1.0.0",
+ "@plugin/contracts": "^0.4.2",
"@openzeppelin/contracts": "^4.7.3",
"axios": "^0.24.0"
}
diff --git a/contracts/requirements.txt b/contracts/requirements.txt
deleted file mode 100644
index 84895f1..0000000
--- a/contracts/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-ecdsa
-fastecdsa
-sympy
-cairo-lang>=0.11.0.1
-starknet-devnet>=0.5.0
-openzeppelin-cairo-contracts==0.5.0
diff --git a/contracts/src/plugin/solidity/emergency/StarknetValidator.sol b/contracts/solidity/emergency/StarknetValidator.sol
similarity index 81%
rename from contracts/src/plugin/solidity/emergency/StarknetValidator.sol
rename to contracts/solidity/emergency/StarknetValidator.sol
index bfe5592..fdd5442 100644
--- a/contracts/src/plugin/solidity/emergency/StarknetValidator.sol
+++ b/contracts/solidity/emergency/StarknetValidator.sol
@@ -1,20 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
-import "@pluginv3.0/contracts/src/v0.8/interfaces/AggregatorValidatorInterface.sol";
-import "@pluginv3.0/contracts/src/v0.8/interfaces/TypeAndVersionInterface.sol";
-import "@pluginv3.0/contracts/src/v0.8/interfaces/AccessControllerInterface.sol";
-import "@pluginv3.0/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
-import "@pluginv3.0/contracts/src/v0.8/SimpleWriteAccessController.sol";
-import "@pluginv3.0/contracts/src/v0.8/dev/vendor/openzeppelin-solidity/v4.3.1/contracts/utils/Address.sol";
-import "../../../../vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessaging.sol";
+import "@plugin/contracts/src/v0.8/interfaces/AggregatorValidatorInterface.sol";
+import "@plugin/contracts/src/v0.8/interfaces/TypeAndVersionInterface.sol";
+import "@plugin/contracts/src/v0.8/interfaces/AccessControllerInterface.sol";
+import "@plugin/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
+import "@plugin/contracts/src/v0.8/SimpleWriteAccessController.sol";
+import "@plugin/contracts/src/v0.8/dev/vendor/openzeppelin-solidity/v4.3.1/contracts/utils/Address.sol";
+import "../../vendor/starkware-libs/cairo-lang/src/starkware/starknet/solidity/IStarknetMessaging.sol";
/// @title StarknetValidator - makes cross chain calls to update the Sequencer Uptime Feed on L2
contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController {
// Config for L1 -> L2 message cost approximation
+ // Message Cost = gasAdjustment * gasEstimate * gasPriceL1Feed / 100
struct GasConfig {
+ // gas units derived from starknet estimate_message_fee
+ // recommended value is 17300 at time of writing
uint256 gasEstimate;
address gasPriceL1Feed;
+ // gasAdjustment of 100 equals 1x (see setGasConfig for more info)
+ // recommended value is 130 (or 1.3x) because at time of writing
+ // L2 gas price is equal to L1 gas price + some margin
+ uint32 gasAdjustment;
}
int256 private constant ANSWER_SEQ_OFFLINE = 1;
@@ -34,13 +41,15 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
error InvalidL2FeedAddress();
/// @notice Error thrown when the source aggregator address is 0
error InvalidSourceAggregatorAddress();
+ /// @notice Error thrown when the access controller address is 0
+ error InvalidAccessControllerAddress();
/// @notice Error thrown when the l1 gas price feed address is 0
error InvalidGasPriceL1FeedAddress();
/// @notice Error thrown when caller is not the owner and does not have access
error AccessForbidden();
/// @notice This event is emitted when the gas config is set.
- event GasConfigSet(uint256 gasEstimate, address indexed gasPriceL1Feed);
+ event GasConfigSet(uint256 gasEstimate, address indexed gasPriceL1Feed, uint32 gasAdjustment);
/// @notice emitted when a new gas access-control contract is set
event ConfigACSet(address indexed previous, address indexed current);
/// @notice emitted when a new source aggregator contract is set
@@ -62,7 +71,8 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
address gasPriceL1Feed,
address source,
uint256 l2Feed,
- uint256 gasEstimate
+ uint256 gasEstimate,
+ uint32 gasAdjustment
) {
if (starknetMessaging == address(0)) {
revert InvalidStarknetMessagingAddress();
@@ -77,7 +87,7 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
_setSourceAggregator(source);
_setConfigAC(configAC);
- _setGasConfig(gasEstimate, gasPriceL1Feed);
+ _setGasConfig(gasEstimate, gasPriceL1Feed, gasAdjustment);
}
/// @notice converts a bool to uint256.
@@ -165,8 +175,14 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
/// @notice L1 oracle is asked for a fast L1 gas price, and the price multiplied by the configured gas estimate
function _approximateFee() internal view returns (uint256) {
+ uint256 gasPrice = approximateGasPrice();
+ return gasPrice * s_gasConfig.gasEstimate;
+ }
+
+ /// @notice calculates the gas price accounting for the gasAdjustment values
+ function approximateGasPrice() public view returns (uint256) {
(, int256 fastGasPriceInWei, , , ) = AggregatorV3Interface(s_gasConfig.gasPriceL1Feed).latestRoundData();
- return uint256(fastGasPriceInWei) * s_gasConfig.gasEstimate;
+ return (uint256(fastGasPriceInWei) * uint256(s_gasConfig.gasAdjustment)) / 100;
}
/**
@@ -185,9 +201,15 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
* @param gasEstimate The estimated units of gas to execute the transaction on L2.
* This value should include any buffer to include.
* @param gasPriceL1Feed The address of the fast gas L1 feed on L1.
+ * @param gasAdjustment Percentage of the the cost to use. Ex: gasAdjustment of 120
+ * means 120% of original value, 1.2x multiplier, or 20% increase (all mean the same thing)
*/
- function setGasConfig(uint256 gasEstimate, address gasPriceL1Feed) external onlyOwnerOrConfigAccess {
- _setGasConfig(gasEstimate, gasPriceL1Feed);
+ function setGasConfig(
+ uint256 gasEstimate,
+ address gasPriceL1Feed,
+ uint32 gasAdjustment
+ ) external onlyOwnerOrConfigAccess {
+ _setGasConfig(gasEstimate, gasPriceL1Feed, gasAdjustment);
}
/**
@@ -195,13 +217,15 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
* @param gasEstimate The estimated units of gas to execute the transaction on L2.
* This value should include any buffer to include.
* @param gasPriceL1Feed The address of the fast gas L1 feed on L1.
+ * @param gasAdjustment Percentage of the the cost to use. Ex: gasAdjustment of 120
+ * means 120% of original value, 1.2x multiplier, or 20% increase (all mean the same thing)
*/
- function _setGasConfig(uint256 gasEstimate, address gasPriceL1Feed) internal {
+ function _setGasConfig(uint256 gasEstimate, address gasPriceL1Feed, uint32 gasAdjustment) internal {
if (gasPriceL1Feed == address(0)) {
revert InvalidGasPriceL1FeedAddress();
}
- s_gasConfig = GasConfig(gasEstimate, gasPriceL1Feed);
- emit GasConfigSet(gasEstimate, gasPriceL1Feed);
+ s_gasConfig = GasConfig(gasEstimate, gasPriceL1Feed, gasAdjustment);
+ emit GasConfigSet(gasEstimate, gasPriceL1Feed, gasAdjustment);
}
/**
@@ -218,6 +242,10 @@ contract StarknetValidator is TypeAndVersionInterface, AggregatorValidatorInterf
* @param accessController The address of the Access Controller for this contract
*/
function _setConfigAC(address accessController) internal {
+ if (accessController == address(0)) {
+ revert InvalidAccessControllerAddress();
+ }
+
address previousAccessController = address(s_configAC);
if (accessController != previousAccessController) {
// NOTICE: we don't give access to the new source aggregator
diff --git a/contracts/src/plugin/solidity/mocks/MockStarknetMessaging.sol b/contracts/solidity/mocks/MockStarknetMessaging.sol
similarity index 86%
rename from contracts/src/plugin/solidity/mocks/MockStarknetMessaging.sol
rename to contracts/solidity/mocks/MockStarknetMessaging.sol
index 319cf13..84ca1c3 100644
--- a/contracts/src/plugin/solidity/mocks/MockStarknetMessaging.sol
+++ b/contracts/solidity/mocks/MockStarknetMessaging.sol
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.6.12;
+pragma solidity ^0.8.0;
-import '../../../../vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/StarknetMessaging.sol';
+import '../../vendor/starkware-libs/cairo-lang/src/starkware/starknet/solidity/StarknetMessaging.sol';
/**
* @title MockStarknetMessaging make cross chain call.
For Devnet L1 <> L2 communication testing, we have to replace IStarknetCore with the MockStarknetMessaging.sol contract
*/
contract MockStarknetMessaging is StarknetMessaging {
- constructor(uint256 MessageCancellationDelay) public {
+ constructor(uint256 MessageCancellationDelay) {
messageCancellationDelay(MessageCancellationDelay);
}
diff --git a/contracts/src/access_control.cairo b/contracts/src/access_control.cairo
new file mode 100644
index 0000000..f66d527
--- /dev/null
+++ b/contracts/src/access_control.cairo
@@ -0,0 +1 @@
+mod access_controller;
diff --git a/contracts/src/access_control/access_controller.cairo b/contracts/src/access_control/access_controller.cairo
new file mode 100644
index 0000000..50de3f2
--- /dev/null
+++ b/contracts/src/access_control/access_controller.cairo
@@ -0,0 +1,61 @@
+#[starknet::contract]
+mod AccessController {
+ use starknet::ContractAddress;
+ use starknet::class_hash::ClassHash;
+
+ use openzeppelin::access::ownable::OwnableComponent;
+
+ use plugin::libraries::access_control::{AccessControlComponent, IAccessController};
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+ use plugin::libraries::upgradeable::{Upgradeable, IUpgradeable};
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ }
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ access_control: AccessControlComponent::Storage,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, owner_address: ContractAddress) {
+ self.ownable.initializer(owner_address);
+ self.access_control.initializer();
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersionImpl of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ 'AccessController 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl UpgradeableImpl of IUpgradeable {
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self.ownable.assert_only_owner();
+ Upgradeable::upgrade(new_impl);
+ }
+ }
+}
diff --git a/contracts/src/account.cairo b/contracts/src/account.cairo
new file mode 100644
index 0000000..dcda746
--- /dev/null
+++ b/contracts/src/account.cairo
@@ -0,0 +1,57 @@
+// copied from https://raw.githubusercontent.com/OpenZeppelin/cairo-contracts/861fc416f87addbe23a3b47f9d19ab27c10d5dc8/src/presets/account.cairo (0.9.0)
+
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts for Cairo v0.9.0 (presets/account.cairo)
+
+/// # Account Preset
+///
+/// OpenZeppelin's basic account which can change its public key and declare, deploy, or call contracts.
+#[starknet::contract(account)]
+mod Account {
+ use openzeppelin::account::AccountComponent;
+ use openzeppelin::introspection::src5::SRC5Component;
+
+ component!(path: AccountComponent, storage: account, event: AccountEvent);
+ component!(path: SRC5Component, storage: src5, event: SRC5Event);
+
+ // Account
+ #[abi(embed_v0)]
+ impl SRC6Impl = AccountComponent::SRC6Impl;
+ #[abi(embed_v0)]
+ impl SRC6CamelOnlyImpl = AccountComponent::SRC6CamelOnlyImpl;
+ #[abi(embed_v0)]
+ impl PublicKeyImpl = AccountComponent::PublicKeyImpl;
+ #[abi(embed_v0)]
+ impl PublicKeyCamelImpl = AccountComponent::PublicKeyCamelImpl;
+ #[abi(embed_v0)]
+ impl DeclarerImpl = AccountComponent::DeclarerImpl;
+ #[abi(embed_v0)]
+ impl DeployableImpl = AccountComponent::DeployableImpl;
+ impl AccountInternalImpl = AccountComponent::InternalImpl;
+
+ // SRC5
+ #[abi(embed_v0)]
+ impl SRC5Impl = SRC5Component::SRC5Impl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ account: AccountComponent::Storage,
+ #[substorage(v0)]
+ src5: SRC5Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ AccountEvent: AccountComponent::Event,
+ #[flat]
+ SRC5Event: SRC5Component::Event
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, public_key: felt252) {
+ self.account.initializer(public_key);
+ }
+}
diff --git a/contracts/src/cairo_project.toml b/contracts/src/cairo_project.toml
new file mode 100644
index 0000000..ab1503c
--- /dev/null
+++ b/contracts/src/cairo_project.toml
@@ -0,0 +1,2 @@
+[crate_roots]
+plugin = "."
diff --git a/contracts/src/emergency.cairo b/contracts/src/emergency.cairo
new file mode 100644
index 0000000..5d04f31
--- /dev/null
+++ b/contracts/src/emergency.cairo
@@ -0,0 +1 @@
+mod sequencer_uptime_feed;
diff --git a/contracts/src/emergency/sequencer_uptime_feed.cairo b/contracts/src/emergency/sequencer_uptime_feed.cairo
new file mode 100644
index 0000000..5b30522
--- /dev/null
+++ b/contracts/src/emergency/sequencer_uptime_feed.cairo
@@ -0,0 +1,318 @@
+use starknet::EthAddress;
+
+#[starknet::interface]
+trait ISequencerUptimeFeed {
+ fn l1_sender(self: @TContractState) -> EthAddress;
+ fn set_l1_sender(ref self: TContractState, address: EthAddress);
+}
+
+#[starknet::contract]
+mod SequencerUptimeFeed {
+ use starknet::EthAddress;
+ use starknet::EthAddressSerde;
+ use starknet::EthAddressIntoFelt252;
+ use starknet::Felt252TryIntoEthAddress;
+ use starknet::EthAddressZeroable;
+ use starknet::ContractAddress;
+ use starknet::StorageBaseAddress;
+ use starknet::SyscallResult;
+ use starknet::storage_read_syscall;
+ use starknet::storage_write_syscall;
+ use starknet::storage_address_from_base_and_offset;
+ use starknet::class_hash::ClassHash;
+
+ use box::BoxTrait;
+ use traits::Into;
+ use traits::TryInto;
+ use option::OptionTrait;
+ use zeroable::Zeroable;
+
+ use openzeppelin::access::ownable::OwnableComponent;
+
+ use plugin::libraries::access_control::{AccessControlComponent, IAccessController};
+ use plugin::libraries::access_control::AccessControlComponent::InternalTrait as AccessControlInternalTrait;
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+ use plugin::ocr2::aggregator::Round;
+ use plugin::ocr2::aggregator::IAggregator;
+ use plugin::ocr2::aggregator::{Transmission};
+ use plugin::libraries::upgradeable::Upgradeable;
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ access_control: AccessControlComponent::Storage,
+ // l1 sender is an starknet validator ethereum address
+ _l1_sender: EthAddress,
+ // maps round id to round transmission
+ _round_transmissions: LegacyMap,
+ _latest_round_id: u128,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ RoundUpdated: RoundUpdated,
+ NewRound: NewRound,
+ AnswerUpdated: AnswerUpdated,
+ UpdateIgnored: UpdateIgnored,
+ L1SenderTransferred: L1SenderTransferred,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct RoundUpdated {
+ status: u128,
+ #[key]
+ updated_at: u64
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct NewRound {
+ #[key]
+ round_id: u128,
+ #[key]
+ started_by: EthAddress,
+ started_at: u64
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct AnswerUpdated {
+ current: u128,
+ #[key]
+ round_id: u128,
+ #[key]
+ timestamp: u64
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct UpdateIgnored {
+ latest_status: u128,
+ #[key]
+ latest_timestamp: u64,
+ incoming_status: u128,
+ #[key]
+ incoming_timestamp: u64
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct L1SenderTransferred {
+ #[key]
+ from_address: EthAddress,
+ #[key]
+ to_address: EthAddress
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersion of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ 'SequencerUptimeFeed 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl AggregatorImpl of IAggregator {
+ fn latest_round_data(self: @ContractState) -> Round {
+ self._require_read_access();
+ let latest_round_id = self._latest_round_id.read();
+ let round_transmission = self._round_transmissions.read(latest_round_id);
+ Round {
+ round_id: latest_round_id.into(),
+ answer: round_transmission.answer,
+ block_num: round_transmission.block_num,
+ started_at: round_transmission.observation_timestamp,
+ updated_at: round_transmission.transmission_timestamp,
+ }
+ }
+
+ fn round_data(self: @ContractState, round_id: u128) -> Round {
+ self._require_read_access();
+ assert(round_id <= self._latest_round_id.read(), 'invalid round id');
+ let round_transmission = self._round_transmissions.read(round_id);
+ Round {
+ round_id: round_id.into(),
+ answer: round_transmission.answer,
+ block_num: round_transmission.block_num,
+ started_at: round_transmission.observation_timestamp,
+ updated_at: round_transmission.transmission_timestamp,
+ }
+ }
+
+ fn description(self: @ContractState) -> felt252 {
+ 'L2 Sequencer Uptime Status Feed'
+ }
+
+ fn decimals(self: @ContractState) -> u8 {
+ 0_u8
+ }
+
+ fn latest_answer(self: @ContractState) -> u128 {
+ self._require_read_access();
+ let latest_round_id = self._latest_round_id.read();
+ let round_transmission = self._round_transmissions.read(latest_round_id);
+ round_transmission.answer
+ }
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, initial_status: u128, owner_address: ContractAddress) {
+ self._initializer(initial_status, owner_address);
+ }
+
+ #[l1_handler]
+ fn update_status(ref self: ContractState, from_address: felt252, status: u128, timestamp: u64) {
+ // Cairo enforces from_address to be a felt252 on the method signature, but we can cast it right after
+ let from_address: EthAddress = from_address.try_into().unwrap();
+ assert(self._l1_sender.read() == from_address, 'EXPECTED_FROM_BRIDGE_ONLY');
+
+ let latest_round_id = self._latest_round_id.read();
+ let latest_round = self._round_transmissions.read(latest_round_id);
+
+ if timestamp <= latest_round.observation_timestamp {
+ self
+ .emit(
+ Event::UpdateIgnored(
+ UpdateIgnored {
+ latest_status: latest_round.answer,
+ latest_timestamp: latest_round.transmission_timestamp,
+ incoming_status: status,
+ incoming_timestamp: timestamp
+ }
+ )
+ );
+ return ();
+ }
+
+ if latest_round.answer == status {
+ self._update_round(latest_round_id, latest_round);
+ } else {
+ // only increment round when status flips
+ let round_id = latest_round_id + 1_u128;
+ self._record_round(from_address, round_id, status, timestamp);
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl SequencerUptimeFeedImpl of super::ISequencerUptimeFeed {
+ fn set_l1_sender(ref self: ContractState, address: EthAddress) {
+ self.ownable.assert_only_owner();
+
+ assert(!address.is_zero(), '0 address not allowed');
+
+ let old_address = self._l1_sender.read();
+
+ if old_address != address {
+ self._l1_sender.write(address);
+ self
+ .emit(
+ Event::L1SenderTransferred(
+ L1SenderTransferred { from_address: old_address, to_address: address }
+ )
+ );
+ }
+ }
+
+ fn l1_sender(self: @ContractState) -> EthAddress {
+ self._l1_sender.read()
+ }
+ }
+
+ ///
+ /// Upgradeable
+ ///
+
+ #[abi(embed_v0)]
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self.ownable.assert_only_owner();
+ Upgradeable::upgrade(new_impl)
+ }
+
+ ///
+ /// Internals
+ ///
+
+ #[generate_trait]
+ impl Internals of InternalTrait {
+ fn _require_read_access(self: @ContractState) {
+ let sender = starknet::info::get_caller_address();
+ self.access_control.check_read_access(sender);
+ }
+
+ fn _initializer(
+ ref self: ContractState, initial_status: u128, owner_address: ContractAddress
+ ) {
+ self.ownable.initializer(owner_address);
+ self.access_control.initializer();
+ let round_id = 1_u128;
+ let timestamp = starknet::info::get_block_timestamp();
+ let from_address = EthAddress {
+ address: 0
+ }; // initial round is set by the constructor, not by an L1 sender
+ self._record_round(from_address, round_id, initial_status, timestamp);
+ }
+
+ fn _record_round(
+ ref self: ContractState,
+ sender: EthAddress,
+ round_id: u128,
+ status: u128,
+ timestamp: u64
+ ) {
+ self._latest_round_id.write(round_id);
+ let block_info = starknet::info::get_block_info().unbox();
+ let block_number = block_info.block_number;
+ let block_timestamp = block_info.block_timestamp;
+
+ let round = Transmission {
+ answer: status,
+ block_num: block_number,
+ observation_timestamp: timestamp,
+ transmission_timestamp: block_timestamp,
+ };
+ self._round_transmissions.write(round_id, round);
+
+ self
+ .emit(
+ Event::NewRound(
+ NewRound { round_id: round_id, started_by: sender, started_at: timestamp }
+ )
+ );
+ self
+ .emit(
+ Event::AnswerUpdated(
+ AnswerUpdated { current: status, round_id: round_id, timestamp: timestamp }
+ )
+ );
+ }
+
+ fn _update_round(ref self: ContractState, round_id: u128, mut round: Transmission) {
+ round.transmission_timestamp = starknet::info::get_block_timestamp();
+ self._round_transmissions.write(round_id, round);
+
+ self
+ .emit(
+ Event::RoundUpdated(
+ RoundUpdated {
+ status: round.answer, updated_at: round.transmission_timestamp
+ }
+ )
+ );
+ }
+ }
+}
diff --git a/contracts/src/lib.cairo b/contracts/src/lib.cairo
new file mode 100644
index 0000000..eef049d
--- /dev/null
+++ b/contracts/src/lib.cairo
@@ -0,0 +1,13 @@
+// All modules must be present here
+
+mod account;
+mod ocr2;
+mod libraries;
+mod utils;
+mod emergency;
+mod multisig;
+mod token;
+mod access_control;
+
+#[cfg(test)]
+mod tests;
diff --git a/contracts/src/libraries.cairo b/contracts/src/libraries.cairo
new file mode 100644
index 0000000..02d6212
--- /dev/null
+++ b/contracts/src/libraries.cairo
@@ -0,0 +1,5 @@
+mod access_control;
+mod token;
+mod upgradeable;
+mod mocks;
+mod type_and_version;
diff --git a/contracts/src/libraries/access_control.cairo b/contracts/src/libraries/access_control.cairo
new file mode 100644
index 0000000..b0a910d
--- /dev/null
+++ b/contracts/src/libraries/access_control.cairo
@@ -0,0 +1,154 @@
+use starknet::ContractAddress;
+#[starknet::interface]
+trait IAccessController {
+ fn has_access(self: @TContractState, user: ContractAddress, data: Array) -> bool;
+ fn has_read_access(self: @TContractState, user: ContractAddress, data: Array) -> bool;
+ fn add_access(ref self: TContractState, user: ContractAddress);
+ fn remove_access(ref self: TContractState, user: ContractAddress);
+ fn enable_access_check(ref self: TContractState);
+ fn disable_access_check(ref self: TContractState);
+}
+
+// Requires Ownable subcomponent.
+#[starknet::component]
+mod AccessControlComponent {
+ use starknet::ContractAddress;
+ use starknet::class_hash::ClassHash;
+ use zeroable::Zeroable;
+
+ use openzeppelin::access::ownable::OwnableComponent;
+
+ use OwnableComponent::InternalImpl as OwnableInternalImpl;
+
+ #[storage]
+ struct Storage {
+ _check_enabled: bool,
+ _access_list: LegacyMap,
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ AddedAccess: AddedAccess,
+ RemovedAccess: RemovedAccess,
+ AccessControlEnabled: AccessControlEnabled,
+ AccessControlDisabled: AccessControlDisabled,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct AddedAccess {
+ #[key]
+ user: ContractAddress
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct RemovedAccess {
+ #[key]
+ user: ContractAddress
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct AccessControlEnabled {}
+
+ #[derive(Drop, starknet::Event)]
+ struct AccessControlDisabled {}
+
+ #[embeddable_as(AccessControlImpl)]
+ impl AccessControl<
+ TContractState,
+ +HasComponent,
+ impl Ownable: OwnableComponent::HasComponent,
+ +Drop,
+ > of super::IAccessController> {
+ fn has_access(
+ self: @ComponentState, user: ContractAddress, data: Array
+ ) -> bool {
+ let has_access = self._access_list.read(user);
+ if has_access {
+ return true;
+ }
+
+ let check_enabled = self._check_enabled.read();
+ if !check_enabled {
+ return true;
+ }
+
+ false
+ }
+
+ fn has_read_access(
+ self: @ComponentState, user: ContractAddress, data: Array
+ ) -> bool {
+ let _has_access = self.has_access(user, data);
+ if _has_access {
+ return true;
+ }
+
+ // NOTICE: read access is granted to direct calls, to enable off-chain reads.
+ if user.is_zero() {
+ return true;
+ }
+
+ false
+ }
+
+ fn add_access(ref self: ComponentState, user: ContractAddress) {
+ get_dep_component!(@self, Ownable).assert_only_owner();
+ let has_access = self._access_list.read(user);
+ if !has_access {
+ self._access_list.write(user, true);
+ self.emit(Event::AddedAccess(AddedAccess { user: user }));
+ }
+ }
+
+ fn remove_access(ref self: ComponentState, user: ContractAddress) {
+ get_dep_component!(@self, Ownable).assert_only_owner();
+ let has_access = self._access_list.read(user);
+ if has_access {
+ self._access_list.write(user, false);
+ self.emit(Event::RemovedAccess(RemovedAccess { user: user }));
+ }
+ }
+
+ fn enable_access_check(ref self: ComponentState) {
+ get_dep_component!(@self, Ownable).assert_only_owner();
+ let check_enabled = self._check_enabled.read();
+ if !check_enabled {
+ self._check_enabled.write(true);
+ self.emit(Event::AccessControlEnabled(AccessControlEnabled {}));
+ }
+ }
+
+ fn disable_access_check(ref self: ComponentState) {
+ get_dep_component!(@self, Ownable).assert_only_owner();
+ let check_enabled = self._check_enabled.read();
+ if check_enabled {
+ self._check_enabled.write(false);
+ self.emit(Event::AccessControlDisabled(AccessControlDisabled {}));
+ }
+ }
+ }
+
+ #[generate_trait]
+ impl InternalImpl<
+ TContractState,
+ +HasComponent,
+ impl Ownable: OwnableComponent::HasComponent,
+ +Drop,
+ > of InternalTrait {
+ fn initializer(ref self: ComponentState) {
+ self._check_enabled.write(true);
+ self.emit(Event::AccessControlEnabled(AccessControlEnabled {}));
+ }
+
+ fn check_access(self: @ComponentState, user: ContractAddress) {
+ let allowed = AccessControl::has_access(self, user, ArrayTrait::new());
+ assert(allowed, 'user does not have access');
+ }
+
+ fn check_read_access(self: @ComponentState, user: ContractAddress) {
+ let allowed = AccessControl::has_read_access(self, user, ArrayTrait::new());
+ assert(allowed, 'user does not have read access');
+ }
+ }
+}
diff --git a/contracts/src/libraries/mocks.cairo b/contracts/src/libraries/mocks.cairo
new file mode 100644
index 0000000..a6e8a73
--- /dev/null
+++ b/contracts/src/libraries/mocks.cairo
@@ -0,0 +1,3 @@
+mod mock_upgradeable;
+mod mock_non_upgradeable;
+mod mock_multisig_target;
diff --git a/contracts/src/libraries/mocks/mock_multisig_target.cairo b/contracts/src/libraries/mocks/mock_multisig_target.cairo
new file mode 100644
index 0000000..686fa97
--- /dev/null
+++ b/contracts/src/libraries/mocks/mock_multisig_target.cairo
@@ -0,0 +1,16 @@
+#[starknet::contract]
+mod MockMultisigTarget {
+ use array::ArrayTrait;
+
+ #[storage]
+ struct Storage {}
+
+ #[abi(per_item)]
+ #[generate_trait]
+ impl HelperImpl of HelperTrait {
+ #[external(v0)]
+ fn increment(ref self: ContractState, val1: felt252, val2: felt252) -> Array {
+ array![val1 + 1, val2 + 1]
+ }
+ }
+}
diff --git a/contracts/src/libraries/mocks/mock_non_upgradeable.cairo b/contracts/src/libraries/mocks/mock_non_upgradeable.cairo
new file mode 100644
index 0000000..921943e
--- /dev/null
+++ b/contracts/src/libraries/mocks/mock_non_upgradeable.cairo
@@ -0,0 +1,20 @@
+#[starknet::interface]
+trait IMockNonUpgradeable {
+ fn bar(self: @TContractState) -> bool;
+}
+
+#[starknet::contract]
+mod MockNonUpgradeable {
+ #[storage]
+ struct Storage {}
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {}
+
+ #[abi(embed_v0)]
+ impl MockNonUpgradeableImpl of super::IMockNonUpgradeable {
+ fn bar(self: @ContractState) -> bool {
+ true
+ }
+ }
+}
diff --git a/contracts/src/libraries/mocks/mock_upgradeable.cairo b/contracts/src/libraries/mocks/mock_upgradeable.cairo
new file mode 100644
index 0000000..1c63112
--- /dev/null
+++ b/contracts/src/libraries/mocks/mock_upgradeable.cairo
@@ -0,0 +1,31 @@
+use starknet::class_hash::ClassHash;
+
+#[starknet::interface]
+trait IMockUpgradeable {
+ fn foo(self: @TContractState) -> bool;
+ fn upgrade(ref self: TContractState, new_impl: ClassHash);
+}
+
+#[starknet::contract]
+mod MockUpgradeable {
+ use starknet::class_hash::ClassHash;
+
+ use plugin::libraries::upgradeable::Upgradeable;
+
+ #[storage]
+ struct Storage {}
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {}
+
+ #[abi(embed_v0)]
+ impl MockUpgradeableImpl of super::IMockUpgradeable {
+ fn foo(self: @ContractState) -> bool {
+ true
+ }
+
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ Upgradeable::upgrade(new_impl)
+ }
+ }
+}
diff --git a/contracts/src/libraries/token.cairo b/contracts/src/libraries/token.cairo
new file mode 100644
index 0000000..b6b4d8d
--- /dev/null
+++ b/contracts/src/libraries/token.cairo
@@ -0,0 +1 @@
+mod erc677;
diff --git a/contracts/src/libraries/token/erc677.cairo b/contracts/src/libraries/token/erc677.cairo
new file mode 100644
index 0000000..20fd6c5
--- /dev/null
+++ b/contracts/src/libraries/token/erc677.cairo
@@ -0,0 +1,86 @@
+use starknet::ContractAddress;
+
+#[starknet::interface]
+trait IERC677 {
+ fn transfer_and_call(
+ ref self: TContractState, to: ContractAddress, value: u256, data: Array
+ ) -> bool;
+}
+
+#[starknet::interface]
+trait IERC677Receiver {
+ fn on_token_transfer(
+ ref self: TContractState, sender: ContractAddress, value: u256, data: Array
+ );
+ // implements EIP-165, where function selectors are defined by Ethereum ABI using the ethereum function signatures
+ fn supports_interface(ref self: TContractState, interface_id: u32) -> bool;
+}
+
+#[starknet::component]
+mod ERC677Component {
+ use starknet::ContractAddress;
+ use openzeppelin::token::erc20::interface::IERC20;
+ use array::ArrayTrait;
+ use array::SpanTrait;
+ use clone::Clone;
+ use array::ArrayTCloneImpl;
+
+ use super::IERC677ReceiverDispatcher;
+ use super::IERC677ReceiverDispatcherTrait;
+
+ // ethereum function selector of "onTokenTransfer(address,uint256,bytes)"
+ const IERC677_RECEIVER_ID: u32 = 0xa4c0ed36_u32;
+
+ #[storage]
+ struct Storage {}
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ TransferAndCall: TransferAndCall,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct TransferAndCall {
+ #[key]
+ from: ContractAddress,
+ #[key]
+ to: ContractAddress,
+ value: u256,
+ data: Array
+ }
+
+ #[embeddable_as(ERC677Impl)]
+ impl ERC677<
+ TContractState,
+ +HasComponent,
+ +IERC20,
+ +Drop,
+ > of super::IERC677> {
+ fn transfer_and_call(
+ ref self: ComponentState,
+ to: ContractAddress,
+ value: u256,
+ data: Array
+ ) -> bool {
+ let sender = starknet::info::get_caller_address();
+
+ let mut contract = self.get_contract_mut();
+ contract.transfer(to, value);
+ self
+ .emit(
+ Event::TransferAndCall(
+ TransferAndCall { from: sender, to: to, value: value, data: data.clone(), }
+ )
+ );
+
+ let receiver = IERC677ReceiverDispatcher { contract_address: to };
+
+ let supports = receiver.supports_interface(IERC677_RECEIVER_ID);
+ if supports {
+ receiver.on_token_transfer(sender, value, data);
+ }
+ true
+ }
+ }
+}
diff --git a/contracts/src/libraries/type_and_version.cairo b/contracts/src/libraries/type_and_version.cairo
new file mode 100644
index 0000000..b048105
--- /dev/null
+++ b/contracts/src/libraries/type_and_version.cairo
@@ -0,0 +1,4 @@
+#[starknet::interface]
+trait ITypeAndVersion {
+ fn type_and_version(self: @TContractState) -> felt252;
+}
diff --git a/contracts/src/libraries/upgradeable.cairo b/contracts/src/libraries/upgradeable.cairo
new file mode 100644
index 0000000..6b9e6af
--- /dev/null
+++ b/contracts/src/libraries/upgradeable.cairo
@@ -0,0 +1,35 @@
+use starknet::class_hash::ClassHash;
+
+// TODO: drop for OZ upgradeable
+
+#[starknet::interface]
+trait IUpgradeable {
+ // note: any contract that uses this module will have a mutable reference to contract state
+ fn upgrade(ref self: TContractState, new_impl: ClassHash);
+}
+
+#[derive(Drop, starknet::Event)]
+struct Upgraded {
+ #[key]
+ new_impl: ClassHash
+}
+
+mod Upgradeable {
+ use zeroable::Zeroable;
+
+ use starknet::SyscallResult;
+ use starknet::SyscallResultTrait;
+ use starknet::syscalls::replace_class_syscall;
+ use starknet::class_hash::ClassHash;
+ use starknet::class_hash::ClassHashZeroable;
+
+ // this method assumes replace_class_syscall has a very low possibility of being deprecated
+ // but if it does, we will either have upgraded the contract to be non-upgradeable by then
+ // because the starknet ecosystem has stabilized or we will be able to upgrade the contract to the proxy pattern
+ // #[internal]
+ fn upgrade(new_impl: ClassHash) {
+ assert(!new_impl.is_zero(), 'Class hash cannot be zero');
+ replace_class_syscall(new_impl).unwrap_syscall();
+ // TODO: Upgraded(new_impl);
+ }
+}
diff --git a/contracts/src/multisig.cairo b/contracts/src/multisig.cairo
new file mode 100644
index 0000000..8f671ca
--- /dev/null
+++ b/contracts/src/multisig.cairo
@@ -0,0 +1,551 @@
+use array::ArrayTrait;
+use option::OptionTrait;
+use starknet::ContractAddress;
+use starknet::class_hash::ClassHash;
+
+fn assert_unique_values<
+ T, impl TCopy: Copy, impl TDrop: Drop, impl TPartialEq: PartialEq,
+>(
+ a: @Array::
+) {
+ let len = a.len();
+ _assert_unique_values_loop(a, len, 0_usize, 1_usize);
+}
+
+fn _assert_unique_values_loop<
+ T, impl TCopy: Copy, impl TDrop: Drop, impl TPartialEq: PartialEq,
+>(
+ a: @Array::, len: usize, j: usize, k: usize
+) {
+ if j >= len {
+ return ();
+ }
+ if k >= len {
+ _assert_unique_values_loop(a, len, j + 1_usize, j + 2_usize);
+ return ();
+ }
+ let j_val = *a.at(j);
+ let k_val = *a.at(k);
+ assert(j_val != k_val, 'duplicate values');
+ _assert_unique_values_loop(a, len, j, k + 1_usize);
+}
+
+#[derive(Copy, Drop, Serde, starknet::Store)]
+struct Transaction {
+ to: ContractAddress,
+ function_selector: felt252,
+ calldata_len: usize,
+ executed: bool,
+ confirmations: usize,
+}
+
+#[starknet::interface]
+trait IMultisig {
+ fn is_signer(self: @TContractState, address: ContractAddress) -> bool;
+ fn get_signers_len(self: @TContractState) -> usize;
+ fn get_signers(self: @TContractState) -> Array;
+ fn get_threshold(self: @TContractState) -> usize;
+ fn get_transactions_len(self: @TContractState) -> u128;
+ fn is_confirmed(self: @TContractState, nonce: u128, signer: ContractAddress) -> bool;
+ fn is_executed(self: @TContractState, nonce: u128) -> bool;
+ fn get_transaction(self: @TContractState, nonce: u128) -> (Transaction, Array::);
+ fn submit_transaction(
+ ref self: TContractState,
+ to: ContractAddress,
+ function_selector: felt252,
+ calldata: Array
+ );
+ fn confirm_transaction(ref self: TContractState, nonce: u128);
+ fn revoke_confirmation(ref self: TContractState, nonce: u128);
+ fn execute_transaction(ref self: TContractState, nonce: u128) -> Array;
+ fn set_threshold(ref self: TContractState, threshold: usize);
+ fn set_signers(ref self: TContractState, signers: Array);
+ fn set_signers_and_threshold(
+ ref self: TContractState, signers: Array, threshold: usize
+ );
+}
+
+#[starknet::contract]
+mod Multisig {
+ use super::assert_unique_values;
+ use super::{Transaction};
+
+ use traits::Into;
+ use traits::TryInto;
+ use zeroable::Zeroable;
+ use array::ArrayTrait;
+ use array::ArrayTCloneImpl;
+ use option::OptionTrait;
+
+ use starknet::ContractAddress;
+ use starknet::ContractAddressIntoFelt252;
+ use starknet::Felt252TryIntoContractAddress;
+ use starknet::StorageBaseAddress;
+ use starknet::SyscallResult;
+ use starknet::SyscallResultTrait;
+ use starknet::call_contract_syscall;
+ use starknet::get_caller_address;
+ use starknet::get_contract_address;
+ use starknet::storage_address_from_base_and_offset;
+ use starknet::storage_read_syscall;
+ use starknet::storage_write_syscall;
+ use starknet::class_hash::ClassHash;
+
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+ use plugin::libraries::upgradeable::{Upgradeable, IUpgradeable};
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ TransactionSubmitted: TransactionSubmitted,
+ TransactionConfirmed: TransactionConfirmed,
+ ConfirmationRevoked: ConfirmationRevoked,
+ TransactionExecuted: TransactionExecuted,
+ SignersSet: SignersSet,
+ ThresholdSet: ThresholdSet,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct TransactionSubmitted {
+ #[key]
+ signer: ContractAddress,
+ #[key]
+ nonce: u128,
+ #[key]
+ to: ContractAddress
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct TransactionConfirmed {
+ #[key]
+ signer: ContractAddress,
+ #[key]
+ nonce: u128
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct ConfirmationRevoked {
+ #[key]
+ signer: ContractAddress,
+ #[key]
+ nonce: u128
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct TransactionExecuted {
+ #[key]
+ executor: ContractAddress,
+ #[key]
+ nonce: u128
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct SignersSet {
+ #[key]
+ signers: Array
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct ThresholdSet {
+ #[key]
+ threshold: usize
+ }
+
+ #[storage]
+ struct Storage {
+ _threshold: usize,
+ _signers: LegacyMap,
+ _is_signer: LegacyMap,
+ _signers_len: usize,
+ _tx_valid_since: u128,
+ _next_nonce: u128,
+ _transactions: LegacyMap,
+ _transaction_calldata: LegacyMap<(u128, usize), felt252>,
+ _is_confirmed: LegacyMap<(u128, ContractAddress), bool>,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, signers: Array, threshold: usize) {
+ let signers_len = signers.len();
+ self._require_valid_threshold(threshold, signers_len);
+ self._set_signers(signers, signers_len);
+ self._set_threshold(threshold);
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersionImpl of ITypeAndVersion {
+ fn type_and_version(self: @ContractState,) -> felt252 {
+ 'Multisig 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl UpgradeableImpl of IUpgradeable {
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self._require_multisig();
+ Upgradeable::upgrade(new_impl)
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl MultisigImpl of super::IMultisig {
+ /// Views
+
+ fn is_signer(self: @ContractState, address: ContractAddress) -> bool {
+ self._is_signer.read(address)
+ }
+
+ fn get_signers_len(self: @ContractState,) -> usize {
+ self._signers_len.read()
+ }
+
+ fn get_signers(self: @ContractState) -> Array {
+ let signers_len = self._signers_len.read();
+ let mut signers = ArrayTrait::new();
+ self._get_signers_range(0_usize, signers_len, ref signers);
+ signers
+ }
+
+ fn get_threshold(self: @ContractState,) -> usize {
+ self._threshold.read()
+ }
+
+ fn get_transactions_len(self: @ContractState,) -> u128 {
+ self._next_nonce.read()
+ }
+
+ fn is_confirmed(self: @ContractState, nonce: u128, signer: ContractAddress) -> bool {
+ self._is_confirmed.read((nonce, signer))
+ }
+
+ fn is_executed(self: @ContractState, nonce: u128) -> bool {
+ let transaction = self._transactions.read(nonce);
+ transaction.executed
+ }
+
+ fn get_transaction(self: @ContractState, nonce: u128) -> (Transaction, Array::) {
+ let transaction = self._transactions.read(nonce);
+
+ let mut calldata = ArrayTrait::new();
+ let calldata_len = transaction.calldata_len;
+ self._get_transaction_calldata_range(nonce, 0_usize, calldata_len, ref calldata);
+
+ (transaction, calldata)
+ }
+
+ /// Externals
+
+ fn submit_transaction(
+ ref self: ContractState,
+ to: ContractAddress,
+ function_selector: felt252,
+ calldata: Array,
+ ) {
+ self._require_signer();
+
+ let nonce = self._next_nonce.read();
+ let calldata_len = calldata.len();
+
+ let transaction = Transaction {
+ to: to,
+ function_selector: function_selector,
+ calldata_len: calldata_len,
+ executed: false,
+ confirmations: 0_usize
+ };
+ self._transactions.write(nonce, transaction);
+
+ self._set_transaction_calldata_range(nonce, 0_usize, calldata_len, @calldata);
+
+ let caller = get_caller_address();
+ self
+ .emit(
+ Event::TransactionSubmitted(
+ TransactionSubmitted { signer: caller, nonce: nonce, to: to }
+ )
+ );
+ self._next_nonce.write(nonce + 1_u128);
+ }
+
+ fn confirm_transaction(ref self: ContractState, nonce: u128) {
+ self._require_signer();
+ self._require_tx_exists(nonce);
+ self._require_tx_valid(nonce);
+ self._require_not_executed(nonce);
+ self._require_not_confirmed(nonce);
+
+ // TODO: write a single field instead of the whole transaction?
+ let mut transaction = self._transactions.read(nonce);
+ transaction.confirmations += 1_usize;
+ self._transactions.write(nonce, transaction);
+
+ let caller = get_caller_address();
+ self._is_confirmed.write((nonce, caller), true);
+
+ self
+ .emit(
+ Event::TransactionConfirmed(
+ TransactionConfirmed { signer: caller, nonce: nonce }
+ )
+ );
+ }
+
+ fn revoke_confirmation(ref self: ContractState, nonce: u128) {
+ self._require_signer();
+ self._require_tx_exists(nonce);
+ self._require_tx_valid(nonce);
+ self._require_not_executed(nonce);
+ self._require_confirmed(nonce);
+
+ // TODO: write a single field instead of the whole transaction?
+ let mut transaction = self._transactions.read(nonce);
+ transaction.confirmations -= 1_usize;
+ self._transactions.write(nonce, transaction);
+
+ let caller = get_caller_address();
+ self._is_confirmed.write((nonce, caller), false);
+
+ self
+ .emit(
+ Event::ConfirmationRevoked(ConfirmationRevoked { signer: caller, nonce: nonce })
+ );
+ }
+
+ fn execute_transaction(ref self: ContractState, nonce: u128) -> Array {
+ self._require_signer();
+ self._require_tx_exists(nonce);
+ self._require_tx_valid(nonce);
+ self._require_not_executed(nonce);
+
+ let mut transaction = self._transactions.read(nonce);
+
+ let threshold = self._threshold.read();
+ assert(threshold <= transaction.confirmations, 'more confirmations required');
+
+ let mut calldata = ArrayTrait::new();
+ let calldata_len = transaction.calldata_len;
+ self._get_transaction_calldata_range(nonce, 0_usize, calldata_len, ref calldata);
+
+ transaction.executed = true;
+ self._transactions.write(nonce, transaction);
+
+ let caller = get_caller_address();
+ self
+ .emit(
+ Event::TransactionExecuted(
+ TransactionExecuted { executor: caller, nonce: nonce }
+ )
+ );
+
+ let response = call_contract_syscall(
+ transaction.to, transaction.function_selector, calldata.span()
+ )
+ .unwrap_syscall();
+
+ // TODO: this shouldn't be necessary. call_contract_syscall returns a Span, which
+ // is a serialized result, but returning a Span results in an error:
+ //
+ // Trait has no implementation in context: core::serde::Serde::>
+ //
+ // Cairo docs also have an example that returns a Span:
+ // https://github.com/starkware-libs/cairo/blob/fe425d0893ff93a936bb3e8bbbac771033074bdb/docs/reference/src/components/cairo/modules/language_constructs/pages/contracts.adoc#L226
+ ArrayTCloneImpl::clone(response.snapshot)
+ }
+
+ fn set_threshold(ref self: ContractState, threshold: usize) {
+ self._require_multisig();
+
+ let signers_len = self._signers_len.read();
+ self._require_valid_threshold(threshold, signers_len);
+
+ self._update_tx_valid_since();
+
+ self._set_threshold(threshold);
+ }
+
+ fn set_signers(ref self: ContractState, signers: Array) {
+ self._require_multisig();
+
+ self._update_tx_valid_since();
+
+ let signers_len = signers.len();
+ self._set_signers(signers, signers_len);
+
+ let threshold = self._threshold.read();
+
+ if signers_len < threshold {
+ self._require_valid_threshold(signers_len, signers_len);
+ self._set_threshold(signers_len);
+ }
+ }
+
+ fn set_signers_and_threshold(
+ ref self: ContractState, signers: Array, threshold: usize
+ ) {
+ self._require_multisig();
+
+ let signers_len = signers.len();
+ self._require_valid_threshold(threshold, signers_len);
+
+ self._update_tx_valid_since();
+
+ self._set_signers(signers, signers_len);
+ self._set_threshold(threshold);
+ }
+ }
+
+ /// Internals
+ #[generate_trait]
+ impl InternalImpl of InternalTrait {
+ fn _set_signers(
+ ref self: ContractState, signers: Array, signers_len: usize
+ ) {
+ self._require_unique_signers(@signers);
+
+ let old_signers_len = self._signers_len.read();
+ self._clean_signers_range(0_usize, old_signers_len);
+
+ self._signers_len.write(signers_len);
+ self._set_signers_range(0_usize, signers_len, @signers);
+
+ self.emit(Event::SignersSet(SignersSet { signers: signers }));
+ }
+
+ fn _clean_signers_range(ref self: ContractState, index: usize, len: usize) {
+ if index >= len {
+ return ();
+ }
+
+ let signer = self._signers.read(index);
+ self._is_signer.write(signer, false);
+ self._signers.write(index, Zeroable::zero());
+
+ self._clean_signers_range(index + 1_usize, len);
+ }
+
+ fn _set_signers_range(
+ ref self: ContractState, index: usize, len: usize, signers: @Array
+ ) {
+ if index >= len {
+ return ();
+ }
+
+ let signer = *signers.at(index);
+ self._signers.write(index, signer);
+ self._is_signer.write(signer, true);
+
+ self._set_signers_range(index + 1_usize, len, signers);
+ }
+
+ fn _get_signers_range(
+ self: @ContractState, index: usize, len: usize, ref signers: Array
+ ) {
+ if index >= len {
+ return ();
+ }
+
+ let signer = self._signers.read(index);
+ signers.append(signer);
+
+ self._get_signers_range(index + 1_usize, len, ref signers);
+ }
+
+ fn _set_transaction_calldata_range(
+ ref self: ContractState,
+ nonce: u128,
+ index: usize,
+ len: usize,
+ calldata: @Array
+ ) {
+ if index >= len {
+ return ();
+ }
+
+ let calldata_arg = *calldata.at(index);
+ self._transaction_calldata.write((nonce, index), calldata_arg);
+
+ self._set_transaction_calldata_range(nonce, index + 1_usize, len, calldata);
+ }
+
+ fn _get_transaction_calldata_range(
+ self: @ContractState,
+ nonce: u128,
+ index: usize,
+ len: usize,
+ ref calldata: Array
+ ) {
+ if index >= len {
+ return ();
+ }
+
+ let calldata_arg = self._transaction_calldata.read((nonce, index));
+ calldata.append(calldata_arg);
+
+ self._get_transaction_calldata_range(nonce, index + 1_usize, len, ref calldata);
+ }
+
+ fn _set_threshold(ref self: ContractState, threshold: usize) {
+ self._threshold.write(threshold);
+ self.emit(Event::ThresholdSet(ThresholdSet { threshold: threshold }));
+ }
+
+ fn _update_tx_valid_since(ref self: ContractState) {
+ let tx_valid_since = self._next_nonce.read();
+ self._tx_valid_since.write(tx_valid_since);
+ }
+
+ fn _require_signer(self: @ContractState) {
+ let caller = get_caller_address();
+ let is_signer = self._is_signer.read(caller);
+ assert(is_signer, 'invalid signer');
+ }
+
+ fn _require_tx_exists(self: @ContractState, nonce: u128) {
+ let next_nonce = self._next_nonce.read();
+ assert(nonce < next_nonce, 'transaction does not exist');
+ }
+
+ fn _require_not_executed(self: @ContractState, nonce: u128) {
+ let transaction = self._transactions.read(nonce);
+ assert(!transaction.executed, 'transaction already executed');
+ }
+
+ fn _require_not_confirmed(self: @ContractState, nonce: u128) {
+ let caller = get_caller_address();
+ let is_confirmed = self._is_confirmed.read((nonce, caller));
+ assert(!is_confirmed, 'transaction already confirmed');
+ }
+
+ fn _require_confirmed(self: @ContractState, nonce: u128) {
+ let caller = get_caller_address();
+ let is_confirmed = self._is_confirmed.read((nonce, caller));
+ assert(is_confirmed, 'transaction not confirmed');
+ }
+
+ fn _require_unique_signers(self: @ContractState, signers: @Array) {
+ assert_unique_values(signers);
+ }
+
+ fn _require_tx_valid(self: @ContractState, nonce: u128) {
+ let tx_valid_since = self._tx_valid_since.read();
+ assert(tx_valid_since <= nonce, 'transaction invalid');
+ }
+
+ fn _require_multisig(self: @ContractState) {
+ let caller = get_caller_address();
+ let contract = get_contract_address();
+ assert(caller == contract, 'only multisig allowed');
+ }
+
+ fn _require_valid_threshold(self: @ContractState, threshold: usize, signers_len: usize) {
+ if threshold == 0_usize {
+ if signers_len == 0_usize {
+ return ();
+ }
+ }
+
+ assert(threshold >= 1_usize, 'invalid threshold, too small');
+ assert(threshold <= signers_len, 'invalid threshold, too large');
+ }
+ }
+}
diff --git a/contracts/src/ocr2.cairo b/contracts/src/ocr2.cairo
new file mode 100644
index 0000000..09a69ef
--- /dev/null
+++ b/contracts/src/ocr2.cairo
@@ -0,0 +1,4 @@
+mod aggregator;
+mod aggregator_proxy;
+mod mocks;
+
diff --git a/contracts/src/ocr2/aggregator.cairo b/contracts/src/ocr2/aggregator.cairo
new file mode 100644
index 0000000..247933d
--- /dev/null
+++ b/contracts/src/ocr2/aggregator.cairo
@@ -0,0 +1,1252 @@
+use starknet::ContractAddress;
+
+#[derive(Copy, Drop, Serde, PartialEq, starknet::Store)]
+struct Round {
+ // used as u128 internally, but necessary for phase-prefixed round ids as returned by proxy
+ round_id: felt252,
+ answer: u128,
+ block_num: u64,
+ started_at: u64,
+ updated_at: u64,
+}
+
+#[derive(Copy, Drop, Serde, starknet::Store)]
+struct Transmission {
+ answer: u128,
+ block_num: u64,
+ observation_timestamp: u64,
+ transmission_timestamp: u64,
+}
+
+// TODO: reintroduce custom storage to save on space
+// impl TransmissionStorageAccess of StorageAccess {
+// fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult:: {
+// let block_num_and_answer = storage_read_syscall(
+// address_domain, storage_address_from_base_and_offset(base, 0_u8)
+// )?;
+// let (block_num, answer) = split_felt(block_num_and_answer);
+// let timestamps = storage_read_syscall(
+// address_domain, storage_address_from_base_and_offset(base, 1_u8)
+// )?;
+// let (observation_timestamp, transmission_timestamp) = split_felt(timestamps);
+
+// Result::Ok(
+// Transmission {
+// answer,
+// block_num: block_num.try_into().unwrap(),
+// observation_timestamp: observation_timestamp.try_into().unwrap(),
+// transmission_timestamp: transmission_timestamp.try_into().unwrap(),
+// }
+// )
+// }
+//
+// fn write(
+// address_domain: u32, base: StorageBaseAddress, value: Transmission
+// ) -> SyscallResult::<()> {
+// let block_num_and_answer = value.block_num.into() * SHIFT_128 + value.answer.into();
+// let timestamps = value.observation_timestamp.into() * SHIFT_128
+// + value.transmission_timestamp.into();
+// storage_write_syscall(
+// address_domain,
+// storage_address_from_base_and_offset(base, 0_u8),
+// block_num_and_answer
+// )?;
+// storage_write_syscall(
+// address_domain, storage_address_from_base_and_offset(base, 1_u8), timestamps
+// )
+// }
+// }
+
+#[starknet::interface]
+trait IAggregator {
+ fn latest_round_data(self: @TContractState) -> Round;
+ fn round_data(self: @TContractState, round_id: u128) -> Round;
+ fn description(self: @TContractState) -> felt252;
+ fn decimals(self: @TContractState) -> u8;
+ fn latest_answer(self: @TContractState) -> u128;
+}
+
+#[derive(Copy, Drop, Serde)]
+struct OracleConfig {
+ signer: felt252,
+ transmitter: ContractAddress,
+}
+
+impl OracleConfigLegacyHash of LegacyHash {
+ fn hash(mut state: felt252, value: OracleConfig) -> felt252 {
+ state = LegacyHash::hash(state, value.signer);
+ state = LegacyHash::hash(state, value.transmitter);
+ state
+ }
+}
+
+#[starknet::interface]
+trait Configuration {
+ fn set_config(
+ ref self: TContractState,
+ oracles: Array,
+ f: u8,
+ onchain_config: Array,
+ offchain_config_version: u64,
+ offchain_config: Array,
+ ) -> felt252; // digest
+ fn latest_config_details(self: @TContractState) -> (u64, u64, felt252);
+ fn transmitters(self: @TContractState) -> Array;
+}
+
+use Aggregator::{BillingConfig, BillingConfigSerde};
+
+#[starknet::interface]
+trait Billing {
+ fn set_billing_access_controller(ref self: TContractState, access_controller: ContractAddress);
+ fn set_billing(ref self: TContractState, config: Aggregator::BillingConfig);
+ fn billing(self: @TContractState) -> Aggregator::BillingConfig;
+ //
+ fn withdraw_payment(ref self: TContractState, transmitter: ContractAddress);
+ fn owed_payment(self: @TContractState, transmitter: ContractAddress) -> u128;
+ fn withdraw_funds(ref self: TContractState, recipient: ContractAddress, amount: u256);
+ fn link_available_for_payment(
+ self: @TContractState
+ ) -> (bool, u128); // (is negative, absolute difference)
+ fn set_link_token(
+ ref self: TContractState, link_token: ContractAddress, recipient: ContractAddress
+ );
+}
+
+#[derive(Copy, Drop, Serde)]
+struct PayeeConfig {
+ transmitter: ContractAddress,
+ payee: ContractAddress,
+}
+
+#[starknet::interface]
+trait PayeeManagement {
+ fn set_payees(ref self: TContractState, payees: Array);
+ fn transfer_payeeship(
+ ref self: TContractState, transmitter: ContractAddress, proposed: ContractAddress
+ );
+ fn accept_payeeship(ref self: TContractState, transmitter: ContractAddress);
+}
+
+use array::ArrayTrait;
+use array::SpanTrait;
+use option::OptionTrait;
+use hash::LegacyHash;
+
+fn hash_span, impl TCopy: Copy>(
+ state: felt252, mut value: Span
+) -> felt252 {
+ let item = value.pop_front();
+ match item {
+ Option::Some(x) => {
+ let s = LegacyHash::hash(state, *x);
+ hash_span(s, value)
+ },
+ Option::None(_) => state,
+ }
+}
+
+// TODO: consider switching to lookups
+fn pow(n: u128, m: u128) -> u128 {
+ if m == 0_u128 {
+ return 1_u128;
+ }
+ let half = pow(n, m / 2_u128);
+ let total = half * half;
+ // TODO: check if (& 1) is cheaper
+ if (m % 2_u128) == 1_u128 {
+ total * n
+ } else {
+ total
+ }
+}
+
+// TODO: wrap hash_span
+impl SpanLegacyHash, impl TCopy: Copy> of LegacyHash> {
+ fn hash(state: felt252, mut value: Span) -> felt252 {
+ hash_span(state, value)
+ }
+}
+
+#[starknet::contract]
+mod Aggregator {
+ use super::Round;
+ use super::{Transmission};
+ use super::SpanLegacyHash;
+ use super::pow;
+
+ use array::ArrayTrait;
+ use array::SpanTrait;
+ use box::BoxTrait;
+ use hash::LegacyHash;
+ use integer::U128IntoFelt252;
+ use integer::u128s_from_felt252;
+ use integer::U128sFromFelt252Result;
+ use zeroable::Zeroable;
+ use traits::Into;
+ use traits::TryInto;
+ use option::OptionTrait;
+
+ use starknet::ContractAddress;
+ use starknet::get_caller_address;
+ use starknet::contract_address_const;
+ use starknet::StorageBaseAddress;
+ use starknet::SyscallResult;
+ use starknet::storage_read_syscall;
+ use starknet::storage_write_syscall;
+ use starknet::storage_address_from_base_and_offset;
+ use starknet::class_hash::ClassHash;
+
+ use openzeppelin::access::ownable::OwnableComponent;
+ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
+
+ use plugin::utils::split_felt;
+ use plugin::libraries::access_control::{AccessControlComponent, IAccessController};
+ use plugin::libraries::access_control::AccessControlComponent::InternalTrait as AccessControlInternalTrait;
+ use plugin::libraries::upgradeable::{Upgradeable, IUpgradeable};
+
+ use plugin::libraries::access_control::{
+ IAccessControllerDispatcher, IAccessControllerDispatcherTrait
+ };
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ const GIGA: u128 = 1000000000_u128;
+
+ const MAX_ORACLES: u32 = 31_u32;
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ NewTransmission: NewTransmission,
+ ConfigSet: ConfigSet,
+ LinkTokenSet: LinkTokenSet,
+ BillingAccessControllerSet: BillingAccessControllerSet,
+ BillingSet: BillingSet,
+ OraclePaid: OraclePaid,
+ PayeeshipTransferRequested: PayeeshipTransferRequested,
+ PayeeshipTransferred: PayeeshipTransferred,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct NewTransmission {
+ #[key]
+ round_id: u128,
+ answer: u128,
+ #[key]
+ transmitter: ContractAddress,
+ observation_timestamp: u64,
+ observers: felt252,
+ observations: Array,
+ juels_per_fee_coin: u128,
+ gas_price: u128,
+ config_digest: felt252,
+ epoch_and_round: u64,
+ reimbursement: u128
+ }
+
+ #[derive(Copy, Drop, Serde, starknet::Store)]
+ struct Oracle {
+ index: usize,
+ // entire supply of PLI always fits into u96, so u128 is safe to use
+ payment_juels: u128,
+ }
+
+ // TODO: reintroduce custom storage to save on space
+ // impl OracleStorageAccess of StorageAccess {
+ // fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult:: {
+ // let value = storage_read_syscall(
+ // address_domain, storage_address_from_base_and_offset(base, 0_u8)
+ // )?;
+ // let (index, payment_juels) = split_felt(value);
+ // Result::Ok(Oracle { index: index.try_into().unwrap(), payment_juels, })
+ // }
+ //
+ // fn write(
+ // address_domain: u32, base: StorageBaseAddress, value: Oracle
+ // ) -> SyscallResult::<()> {
+ // let value = value.index.into() * SHIFT_128 + value.payment_juels.into();
+ // storage_write_syscall(
+ // address_domain, storage_address_from_base_and_offset(base, 0_u8), value
+ // )
+ // }
+ // }
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ access_control: AccessControlComponent::Storage,
+ /// Maximum number of faulty oracles
+ _f: u8,
+ _latest_epoch_and_round: u64, // (u32, u32)
+ _latest_aggregator_round_id: u128,
+ _min_answer: u128,
+ _max_answer: u128,
+ _decimals: u8,
+ _description: felt252,
+ _latest_config_block_number: u64,
+ _config_count: u64,
+ _latest_config_digest: felt252,
+ // _oracles: Array, // NOTE: array can't be used in storage
+ _oracles_len: usize,
+ _transmitters: LegacyMap, //
+ _signers: LegacyMap, //
+ _signers_list: LegacyMap,
+ _transmitters_list: LegacyMap,
+ _reward_from_aggregator_round_id: LegacyMap, //
+ _transmissions: LegacyMap,
+ // link token
+ _link_token: ContractAddress,
+ // billing
+ _billing_access_controller: ContractAddress,
+ _billing: BillingConfig,
+ // payee management
+ _payees: LegacyMap, //
+ _proposed_payees: LegacyMap<
+ ContractAddress, ContractAddress
+ > //
+ }
+
+ #[generate_trait]
+ impl AccessHelperImpl of AccessHelperTrait {
+ fn _require_read_access(self: @ContractState) {
+ let caller = starknet::info::get_caller_address();
+ self.access_control.check_read_access(caller);
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersionImpl of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ 'ocr2/aggregator.cairo 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl AggregatorImpl of super::IAggregator {
+ fn latest_round_data(self: @ContractState) -> Round {
+ self._require_read_access();
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let transmission = self._transmissions.read(latest_round_id);
+ Round {
+ round_id: latest_round_id.into(),
+ answer: transmission.answer,
+ block_num: transmission.block_num,
+ started_at: transmission.observation_timestamp,
+ updated_at: transmission.transmission_timestamp,
+ }
+ }
+
+ fn round_data(self: @ContractState, round_id: u128) -> Round {
+ self._require_read_access();
+ let transmission = self._transmissions.read(round_id);
+ Round {
+ round_id: round_id.into(),
+ answer: transmission.answer,
+ block_num: transmission.block_num,
+ started_at: transmission.observation_timestamp,
+ updated_at: transmission.transmission_timestamp,
+ }
+ }
+
+ fn description(self: @ContractState) -> felt252 {
+ self._require_read_access();
+ self._description.read()
+ }
+
+ fn decimals(self: @ContractState) -> u8 {
+ self._require_read_access();
+ self._decimals.read()
+ }
+
+ fn latest_answer(self: @ContractState) -> u128 {
+ self._require_read_access();
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let transmission = self._transmissions.read(latest_round_id);
+ transmission.answer
+ }
+ }
+
+ // ---
+
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ owner: ContractAddress,
+ link: ContractAddress,
+ min_answer: u128,
+ max_answer: u128,
+ billing_access_controller: ContractAddress,
+ decimals: u8,
+ description: felt252
+ ) {
+ self.ownable.initializer(owner);
+ self.access_control.initializer();
+ self._link_token.write(link);
+ self._billing_access_controller.write(billing_access_controller);
+
+ assert(min_answer < max_answer, 'min >= max');
+ self._min_answer.write(min_answer);
+ self._max_answer.write(max_answer);
+
+ self._decimals.write(decimals);
+ self._description.write(description);
+ }
+
+ // --- Upgradeable ---
+
+ #[abi(embed_v0)]
+ impl UpgradeableImpl of IUpgradeable {
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self.ownable.assert_only_owner();
+ Upgradeable::upgrade(new_impl)
+ }
+ }
+
+ // --- Validation ---
+
+ // NOTE: Currently unimplemented:
+
+ // --- Configuration
+
+ #[derive(Drop, starknet::Event)]
+ struct ConfigSet {
+ #[key]
+ previous_config_block_number: u64,
+ #[key]
+ latest_config_digest: felt252,
+ config_count: u64,
+ oracles: Array,
+ f: u8,
+ onchain_config: Array,
+ offchain_config_version: u64,
+ offchain_config: Array,
+ }
+
+ use super::OracleConfig;
+
+ const SHIFT_128: felt252 = 0x100000000000000000000000000000000;
+ // 4 * 2 ** (124 - 12)
+ const HALF_PREFIX: u128 = 0x40000000000000000000000000000_u128;
+ // 2 ** (124 - 12) - 1
+ const HALF_DIGEST_MASK: u128 = 0xffffffffffffffffffffffffffff_u128;
+
+ fn config_digest_from_data(
+ chain_id: felt252,
+ contract_address: ContractAddress,
+ config_count: u64,
+ oracles: @Array,
+ f: u8,
+ onchain_config: @Array,
+ offchain_config_version: u64,
+ offchain_config: @Array,
+ ) -> felt252 {
+ let mut state = 0;
+ state = LegacyHash::hash(state, chain_id);
+ state = LegacyHash::hash(state, contract_address);
+ state = LegacyHash::hash(state, config_count);
+ state = LegacyHash::hash(state, oracles.len());
+ state = LegacyHash::hash(state, oracles.span()); // for oracle in oracles, hash each
+ state = LegacyHash::hash(state, f);
+ state = LegacyHash::hash(state, onchain_config.len());
+ state = LegacyHash::hash(state, onchain_config.span());
+ state = LegacyHash::hash(state, offchain_config_version);
+ state = LegacyHash::hash(state, offchain_config.len());
+ state = LegacyHash::hash(state, offchain_config.span());
+ let len: usize = 3
+ + 1
+ + (oracles.len() * 2)
+ + 1
+ + 1
+ + onchain_config.len()
+ + 1
+ + 1
+ + offchain_config.len();
+ state = LegacyHash::hash(state, len);
+
+ // since there's no bitwise ops on felt252, we split into two u128s and recombine.
+ // we only need to clamp and prefix the top bits.
+ let (top, bottom) = split_felt(state);
+ let masked_top = (top & HALF_DIGEST_MASK) | HALF_PREFIX;
+ let masked = (masked_top.into() * SHIFT_128) + bottom.into();
+
+ masked
+ }
+
+ #[abi(embed_v0)]
+ impl ConfigurationImpl of super::Configuration {
+ fn set_config(
+ ref self: ContractState,
+ oracles: Array,
+ f: u8,
+ onchain_config: Array,
+ offchain_config_version: u64,
+ offchain_config: Array,
+ ) -> felt252 { // digest
+ self.ownable.assert_only_owner();
+ assert(oracles.len() <= MAX_ORACLES, 'too many oracles');
+ assert((3_u8 * f).into() < oracles.len(), 'faulty-oracle f too high');
+ assert(f > 0_u8, 'f must be positive');
+
+ assert(onchain_config.len() == 0_u32, 'onchain_config must be empty');
+
+ let min_answer = self._min_answer.read();
+ let max_answer = self._max_answer.read();
+
+ let mut computed_onchain_config = ArrayTrait::new();
+ computed_onchain_config.append(1); // version
+ computed_onchain_config.append(min_answer.into());
+ computed_onchain_config.append(max_answer.into());
+
+ self.pay_oracles();
+
+ // remove old signers & transmitters
+ self.remove_oracles();
+
+ let latest_round_id = self._latest_aggregator_round_id.read();
+
+ self.add_oracles(@oracles, latest_round_id);
+
+ self._f.write(f);
+ let block_num = starknet::info::get_block_info().unbox().block_number;
+ let prev_block_num = self._latest_config_block_number.read();
+ self._latest_config_block_number.write(block_num);
+ // update config count
+ let mut config_count = self._config_count.read();
+ config_count += 1_u64;
+ self._config_count.write(config_count);
+ let contract_address = starknet::info::get_contract_address();
+ let chain_id = starknet::info::get_tx_info().unbox().chain_id;
+
+ let digest = config_digest_from_data(
+ chain_id,
+ contract_address,
+ config_count,
+ @oracles,
+ f,
+ @computed_onchain_config,
+ offchain_config_version,
+ @offchain_config,
+ );
+
+ self._latest_config_digest.write(digest);
+
+ // reset epoch & round
+ self._latest_epoch_and_round.write(0_u64);
+
+ self
+ .emit(
+ Event::ConfigSet(
+ ConfigSet {
+ previous_config_block_number: prev_block_num,
+ latest_config_digest: digest,
+ config_count: config_count,
+ oracles: oracles,
+ f: f,
+ onchain_config: computed_onchain_config,
+ offchain_config_version: offchain_config_version,
+ offchain_config: offchain_config
+ }
+ )
+ );
+
+ digest
+ }
+
+ fn latest_config_details(self: @ContractState) -> (u64, u64, felt252) {
+ let config_count = self._config_count.read();
+ let block_number = self._latest_config_block_number.read();
+ let config_digest = self._latest_config_digest.read();
+
+ (config_count, block_number, config_digest)
+ }
+
+ fn transmitters(self: @ContractState) -> Array {
+ let mut index = 1;
+ let mut len = self._oracles_len.read();
+ let mut result = ArrayTrait::new();
+ while len > 0_usize {
+ let transmitter = self._transmitters_list.read(index);
+ result.append(transmitter);
+ len -= 1;
+ index += 1;
+ };
+ return result;
+ }
+ }
+
+ #[generate_trait]
+ impl ConfigurationHelperImpl of ConfigurationHelperTrait {
+ fn remove_oracles(ref self: ContractState) {
+ let mut index = self._oracles_len.read();
+ while index > 0_usize {
+ let signer = self._signers_list.read(index);
+ self._signers.write(signer, 0_usize);
+
+ let transmitter = self._transmitters_list.read(index);
+ self
+ ._transmitters
+ .write(transmitter, Oracle { index: 0_usize, payment_juels: 0_u128 });
+
+ index -= 1;
+ };
+ self._oracles_len.write(0_usize);
+ }
+
+ fn add_oracles(
+ ref self: ContractState, oracles: @Array, latest_round_id: u128
+ ) {
+ let mut index = 0;
+ let mut span = oracles.span();
+ while let Option::Some(oracle) = span
+ .pop_front() {
+ // NOTE: index should start with 1 here because storage is 0-initialized.
+ // That way signers(pkey) => 0 indicates "not present"
+ // This is why we increment first, before using the index
+ index += 1;
+
+ // check for duplicates
+ let existing_signer = self._signers.read(*oracle.signer);
+ assert(existing_signer == 0_usize, 'repeated signer');
+
+ let existing_transmitter = self._transmitters.read(*oracle.transmitter);
+ assert(existing_transmitter.index == 0_usize, 'repeated transmitter');
+
+ self._signers.write(*oracle.signer, index);
+ self._signers_list.write(index, *oracle.signer);
+
+ self
+ ._transmitters
+ .write(*oracle.transmitter, Oracle { index, payment_juels: 0_u128 });
+ self._transmitters_list.write(index, *oracle.transmitter);
+
+ self._reward_from_aggregator_round_id.write(index, latest_round_id);
+ };
+ self._oracles_len.write(index);
+ }
+ }
+
+ // --- Transmission ---
+
+ #[derive(Copy, Drop, Serde)]
+ struct Signature {
+ r: felt252,
+ s: felt252,
+ public_key: felt252,
+ }
+
+ #[derive(Copy, Drop, Serde)]
+ struct ReportContext {
+ config_digest: felt252,
+ epoch_and_round: u64,
+ extra_hash: felt252,
+ }
+
+ #[abi(per_item)]
+ #[generate_trait]
+ impl TransmissionHelperImpl of TransmissionHelperTrait {
+ fn hash_report(
+ self: @ContractState,
+ report_context: @ReportContext,
+ observation_timestamp: u64,
+ observers: felt252,
+ observations: @Array,
+ juels_per_fee_coin: u128,
+ gas_price: u128
+ ) -> felt252 {
+ let mut state = 0;
+ state = LegacyHash::hash(state, *report_context.config_digest);
+ state = LegacyHash::hash(state, *report_context.epoch_and_round);
+ state = LegacyHash::hash(state, *report_context.extra_hash);
+ state = LegacyHash::hash(state, observation_timestamp);
+ state = LegacyHash::hash(state, observers);
+ state = LegacyHash::hash(state, observations.len());
+ state = LegacyHash::hash(state, observations.span());
+ state = LegacyHash::hash(state, juels_per_fee_coin);
+ state = LegacyHash::hash(state, gas_price);
+ let len: usize = 5 + 1 + observations.len() + 2;
+ state = LegacyHash::hash(state, len);
+ state
+ }
+
+ #[external(v0)]
+ fn latest_transmission_details(self: @ContractState) -> (felt252, u64, u128, u64) {
+ let config_digest = self._latest_config_digest.read();
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let epoch_and_round = self._latest_epoch_and_round.read();
+ let transmission = self._transmissions.read(latest_round_id);
+ (
+ config_digest,
+ epoch_and_round,
+ transmission.answer,
+ transmission.transmission_timestamp
+ )
+ }
+
+ #[external(v0)]
+ fn transmit(
+ ref self: ContractState,
+ report_context: ReportContext,
+ observation_timestamp: u64,
+ observers: felt252,
+ observations: Array,
+ juels_per_fee_coin: u128,
+ gas_price: u128,
+ mut signatures: Array,
+ ) {
+ let signatures_len = signatures.len();
+
+ let epoch_and_round = self._latest_epoch_and_round.read();
+ assert(epoch_and_round < report_context.epoch_and_round, 'stale report');
+
+ // validate transmitter
+ let caller = starknet::info::get_caller_address();
+ let mut oracle = self._transmitters.read(caller);
+ assert(oracle.index != 0_usize, 'unknown sender'); // 0 index = uninitialized
+
+ // Validate config digest matches latest_config_digest
+ let config_digest = self._latest_config_digest.read();
+ assert(report_context.config_digest == config_digest, 'config digest mismatch');
+
+ let f = self._f.read();
+ assert(signatures_len == (f + 1_u8).into(), 'wrong number of signatures');
+
+ let msg = self
+ .hash_report(
+ @report_context,
+ observation_timestamp,
+ observers,
+ @observations,
+ juels_per_fee_coin,
+ gas_price
+ );
+
+ // Check all signatures are unique (we only saw each pubkey once)
+ // NOTE: This relies on protocol-level design constraints (MAX_ORACLES = 31, f = 10) which
+ // ensures we have enough bits to store a count for each oracle. Whenever the MAX_ORACLES
+ // is updated, the signed_count parameter should be reconsidered.
+ //
+ // Although 31 bits is enough, we use a u128 here for simplicity because BitAnd and BitOr
+ // operators are defined only for u128 and u256.
+ assert(MAX_ORACLES == 31_u32, '');
+ self.verify_signatures(msg, ref signatures, 0_u128);
+
+ // report():
+
+ let observations_len = observations.len();
+ assert(observations_len <= MAX_ORACLES, '');
+ assert(f.into() < observations_len, '');
+
+ self._latest_epoch_and_round.write(report_context.epoch_and_round);
+
+ let median_idx = observations_len / 2_usize;
+ let median = *observations[median_idx];
+
+ // Validate median in min-max range
+ let min_answer = self._min_answer.read();
+ let max_answer = self._max_answer.read();
+ assert(
+ (min_answer <= median) & (median <= max_answer), 'median is out of min-max range'
+ );
+
+ let prev_round_id = self._latest_aggregator_round_id.read();
+ let round_id = prev_round_id + 1_u128;
+ self._latest_aggregator_round_id.write(round_id);
+
+ let block_info = starknet::info::get_block_info().unbox();
+
+ self
+ ._transmissions
+ .write(
+ round_id,
+ Transmission {
+ answer: median,
+ block_num: block_info.block_number,
+ observation_timestamp,
+ transmission_timestamp: block_info.block_timestamp,
+ }
+ );
+
+ // NOTE: Usually validating via validator would happen here, currently disabled
+
+ let billing = self._billing.read();
+ let reimbursement_juels = calculate_reimbursement(
+ juels_per_fee_coin, signatures_len, gas_price, billing
+ );
+
+ // end report()
+
+ self
+ .emit(
+ Event::NewTransmission(
+ NewTransmission {
+ round_id: round_id,
+ answer: median,
+ transmitter: caller,
+ observation_timestamp: observation_timestamp,
+ observers: observers,
+ observations: observations,
+ juels_per_fee_coin: juels_per_fee_coin,
+ gas_price: gas_price,
+ config_digest: report_context.config_digest,
+ epoch_and_round: report_context.epoch_and_round,
+ reimbursement: reimbursement_juels,
+ }
+ )
+ );
+
+ // pay transmitter
+ let payment = reimbursement_juels + (billing.transmission_payment_gjuels.into() * GIGA);
+ // TODO: check overflow
+
+ oracle.payment_juels += payment;
+ self._transmitters.write(caller, oracle);
+ }
+
+ fn verify_signatures(
+ self: @ContractState,
+ msg: felt252,
+ ref signatures: Array,
+ mut signed_count: u128
+ ) {
+ let mut span = signatures.span();
+ while let Option::Some(signature) = span
+ .pop_front() {
+ let index = self._signers.read(*signature.public_key);
+ assert(index != 0_usize, 'invalid signer'); // 0 index == uninitialized
+
+ let indexed_bit = pow(2_u128, index.into() - 1_u128);
+ let prev_signed_count = signed_count;
+ signed_count = signed_count | indexed_bit;
+ assert(prev_signed_count != signed_count, 'duplicate signer');
+
+ let is_valid = ecdsa::check_ecdsa_signature(
+ msg, *signature.public_key, *signature.r, *signature.s
+ );
+
+ assert(is_valid, '');
+ };
+ }
+ }
+
+ // --- Billing Config
+
+ #[derive(Copy, Drop, Serde, starknet::Store)]
+ struct BillingConfig {
+ observation_payment_gjuels: u32,
+ transmission_payment_gjuels: u32,
+ gas_base: u32,
+ gas_per_signature: u32,
+ }
+
+ // --- Billing Access Controller
+
+ #[derive(Drop, starknet::Event)]
+ struct BillingAccessControllerSet {
+ #[key]
+ old_controller: ContractAddress,
+ #[key]
+ new_controller: ContractAddress,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct BillingSet {
+ config: BillingConfig
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct OraclePaid {
+ #[key]
+ transmitter: ContractAddress,
+ payee: ContractAddress,
+ amount: u256,
+ link_token: ContractAddress,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct LinkTokenSet {
+ #[key]
+ old_link_token: ContractAddress,
+ #[key]
+ new_link_token: ContractAddress
+ }
+
+ #[abi(embed_v0)]
+ impl BillingImpl of super::Billing {
+ fn set_link_token(
+ ref self: ContractState, link_token: ContractAddress, recipient: ContractAddress
+ ) {
+ self.ownable.assert_only_owner();
+
+ let old_token = self._link_token.read();
+
+ if link_token == old_token {
+ return ();
+ }
+
+ let contract_address = starknet::info::get_contract_address();
+
+ // call balanceOf as a sanity check to confirm we're talking to a token
+ let token = IERC20Dispatcher { contract_address: link_token };
+ token.balance_of(account: contract_address);
+
+ self.pay_oracles();
+
+ // transfer remaining balance of old token to recipient
+ let old_token_dispatcher = IERC20Dispatcher { contract_address: old_token };
+ let amount = old_token_dispatcher.balance_of(account: contract_address);
+ old_token_dispatcher.transfer(recipient, amount);
+
+ self._link_token.write(link_token);
+
+ self
+ .emit(
+ Event::LinkTokenSet(
+ LinkTokenSet { old_link_token: old_token, new_link_token: link_token }
+ )
+ );
+ }
+
+ fn set_billing_access_controller(
+ ref self: ContractState, access_controller: ContractAddress
+ ) {
+ self.ownable.assert_only_owner();
+
+ let old_controller = self._billing_access_controller.read();
+ if access_controller == old_controller {
+ return ();
+ }
+
+ self._billing_access_controller.write(access_controller);
+ self
+ .emit(
+ Event::BillingAccessControllerSet(
+ BillingAccessControllerSet {
+ old_controller: old_controller, new_controller: access_controller
+ }
+ )
+ );
+ }
+
+ fn set_billing(ref self: ContractState, config: BillingConfig) {
+ self.has_billing_access();
+
+ self.pay_oracles();
+
+ self._billing.write(config);
+
+ self.emit(Event::BillingSet(BillingSet { config: config }));
+ }
+
+ fn billing(self: @ContractState) -> BillingConfig {
+ self._billing.read()
+ }
+
+ // Payments and Withdrawals
+
+ fn withdraw_payment(ref self: ContractState, transmitter: ContractAddress) {
+ let caller = starknet::info::get_caller_address();
+ let payee = self._payees.read(transmitter);
+ assert(caller == payee, 'only payee can withdraw');
+
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let link_token = self._link_token.read();
+ self.pay_oracle(transmitter, latest_round_id, link_token)
+ }
+
+ fn owed_payment(self: @ContractState, transmitter: ContractAddress) -> u128 {
+ let oracle = self._transmitters.read(transmitter);
+ self._owed_payment(@oracle)
+ }
+
+ fn withdraw_funds(ref self: ContractState, recipient: ContractAddress, amount: u256) {
+ self.has_billing_access();
+
+ let link_token = self._link_token.read();
+ let contract_address = starknet::info::get_contract_address();
+
+ let due = self.total_link_due();
+ // NOTE: equivalent to converting u128 to u256
+ let due = u256 { high: 0_u128, low: due };
+
+ let token = IERC20Dispatcher { contract_address: link_token };
+ let balance = token.balance_of(account: contract_address);
+
+ assert(due <= balance, 'amount due exceeds balance');
+ let available = balance - due;
+
+ // Transfer as much as there is available
+ let amount = if available < amount {
+ available
+ } else {
+ amount
+ };
+ token.transfer(recipient, amount);
+ }
+
+ fn link_available_for_payment(
+ self: @ContractState
+ ) -> (bool, u128) { // (is negative, absolute difference)
+ let link_token = self._link_token.read();
+ let contract_address = starknet::info::get_contract_address();
+
+ let token = IERC20Dispatcher { contract_address: link_token };
+ let balance = token.balance_of(account: contract_address);
+ // entire link supply fits into u96 so this should not fail
+ assert(balance.high == 0_u128, 'balance too high');
+ let balance: u128 = balance.low;
+
+ let due = self.total_link_due();
+ if balance > due {
+ (false, balance - due)
+ } else {
+ (true, due - balance)
+ }
+ }
+ }
+
+ #[generate_trait]
+ impl BillingHelperImpl of BillingHelperTrait {
+ fn has_billing_access(self: @ContractState) {
+ let caller = starknet::info::get_caller_address();
+ let owner = self.ownable.owner();
+
+ // owner always has access
+ if caller == owner {
+ return ();
+ }
+
+ let access_controller = self._billing_access_controller.read();
+ let access_controller = IAccessControllerDispatcher {
+ contract_address: access_controller
+ };
+ assert(
+ access_controller.has_access(caller, ArrayTrait::new()),
+ 'caller does not have access'
+ );
+ }
+
+ // --- Payments and Withdrawals
+
+ fn _owed_payment(self: @ContractState, oracle: @Oracle) -> u128 {
+ if *oracle.index == 0_usize {
+ return 0_u128;
+ }
+
+ let billing = self._billing.read();
+
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let from_round_id = self._reward_from_aggregator_round_id.read(*oracle.index);
+ let rounds = latest_round_id - from_round_id;
+
+ (rounds * billing.observation_payment_gjuels.into() * GIGA) + *oracle.payment_juels
+ }
+
+ fn pay_oracle(
+ ref self: ContractState,
+ transmitter: ContractAddress,
+ latest_round_id: u128,
+ link_token: ContractAddress
+ ) {
+ let oracle = self._transmitters.read(transmitter);
+ if oracle.index == 0_usize {
+ return ();
+ }
+
+ let amount = self._owed_payment(@oracle);
+ // if zero, fastpath return to avoid empty transfers
+ if amount == 0_u128 {
+ return ();
+ }
+
+ let payee = self._payees.read(transmitter);
+
+ // NOTE: equivalent to converting u128 to u256
+ let amount = u256 { high: 0_u128, low: amount };
+
+ let token = IERC20Dispatcher { contract_address: link_token };
+ token.transfer(recipient: payee, amount: amount);
+
+ // Reset payment
+ self._reward_from_aggregator_round_id.write(oracle.index, latest_round_id);
+ self
+ ._transmitters
+ .write(transmitter, Oracle { index: oracle.index, payment_juels: 0_u128 });
+
+ self
+ .emit(
+ Event::OraclePaid(
+ OraclePaid {
+ transmitter: transmitter,
+ payee: payee,
+ amount: amount,
+ link_token: link_token
+ }
+ )
+ );
+ }
+
+ fn pay_oracles(ref self: ContractState) {
+ let mut index = self._oracles_len.read();
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let link_token = self._link_token.read();
+ while index > 0_usize {
+ let transmitter = self._transmitters_list.read(index);
+ self.pay_oracle(transmitter, latest_round_id, link_token);
+ index -= 1;
+ };
+ }
+
+ fn total_link_due(self: @ContractState) -> u128 {
+ let mut index = self._oracles_len.read();
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let mut total_rounds = 0;
+ let mut payments_juels = 0;
+
+ loop {
+ if index == 0_usize {
+ break ();
+ }
+ let transmitter = self._transmitters_list.read(index);
+ let oracle = self._transmitters.read(transmitter);
+ assert(oracle.index != 0_usize, index.into()); // 0 == undefined
+
+ let from_round_id = self._reward_from_aggregator_round_id.read(oracle.index);
+ let rounds = latest_round_id - from_round_id;
+ total_rounds += rounds;
+ payments_juels += oracle.payment_juels;
+ index -= 1;
+ };
+
+ let billing = self._billing.read();
+ return (total_rounds * billing.observation_payment_gjuels.into() * GIGA)
+ + payments_juels;
+ }
+ }
+
+ // --- Transmitter Payment
+
+ const MARGIN: u128 = 115_u128;
+
+ fn calculate_reimbursement(
+ juels_per_fee_coin: u128, signature_count: usize, gas_price: u128, config: BillingConfig
+ ) -> u128 {
+ // TODO: determine new values for these constants
+ // Based on estimateFee (f=1 14977, f=2 14989, f=3 15002 f=4 15014 f=5 15027, count = f+1)
+ // gas_base = 14951, gas_per_signature = 13
+ let signature_count_u128: u128 = signature_count.into();
+ let gas_base_u128: u128 = config.gas_base.into();
+ let gas_per_signature_u128: u128 = config.gas_per_signature.into();
+
+ let exact_gas = gas_base_u128 + (signature_count_u128 * gas_per_signature_u128);
+ let gas = exact_gas * MARGIN / 100_u128; // scale to 115% for some margin
+ let amount = gas * gas_price;
+ amount * juels_per_fee_coin
+ }
+
+ // --- Payee Management
+
+ use super::PayeeConfig;
+
+ #[derive(Drop, starknet::Event)]
+ struct PayeeshipTransferRequested {
+ #[key]
+ transmitter: ContractAddress,
+ #[key]
+ current: ContractAddress,
+ #[key]
+ proposed: ContractAddress,
+ }
+
+ #[derive(Drop, starknet::Event)]
+ struct PayeeshipTransferred {
+ #[key]
+ transmitter: ContractAddress,
+ #[key]
+ previous: ContractAddress,
+ #[key]
+ current: ContractAddress,
+ }
+
+ #[abi(embed_v0)]
+ impl PayeeManagementImpl of super::PayeeManagement {
+ fn set_payees(ref self: ContractState, mut payees: Array) {
+ self.ownable.assert_only_owner();
+ while let Option::Some(payee) = payees
+ .pop_front() {
+ let current_payee = self._payees.read(payee.transmitter);
+ let is_unset = current_payee.is_zero();
+ let is_same = current_payee == payee.payee;
+ assert(is_unset | is_same, 'payee already set');
+
+ self._payees.write(payee.transmitter, payee.payee);
+
+ self
+ .emit(
+ Event::PayeeshipTransferred(
+ PayeeshipTransferred {
+ transmitter: payee.transmitter,
+ previous: current_payee,
+ current: payee.payee
+ }
+ )
+ );
+ }
+ }
+
+ fn transfer_payeeship(
+ ref self: ContractState, transmitter: ContractAddress, proposed: ContractAddress
+ ) {
+ assert(!proposed.is_zero(), 'cannot transfer to zero address');
+ let caller = starknet::info::get_caller_address();
+ let payee = self._payees.read(transmitter);
+ assert(caller == payee, 'only current payee can update');
+ assert(caller != proposed, 'cannot transfer to self');
+
+ self._proposed_payees.write(transmitter, proposed);
+ self
+ .emit(
+ Event::PayeeshipTransferRequested(
+ PayeeshipTransferRequested {
+ transmitter: transmitter, current: payee, proposed: proposed
+ }
+ )
+ );
+ }
+
+ fn accept_payeeship(ref self: ContractState, transmitter: ContractAddress) {
+ let proposed = self._proposed_payees.read(transmitter);
+ let caller = starknet::info::get_caller_address();
+ assert(caller == proposed, 'only proposed payee can accept');
+ let previous = self._payees.read(transmitter);
+
+ self._payees.write(transmitter, proposed);
+ self._proposed_payees.write(transmitter, Zeroable::zero());
+ self
+ .emit(
+ Event::PayeeshipTransferred(
+ PayeeshipTransferred {
+ transmitter: transmitter, previous: previous, current: caller
+ }
+ )
+ );
+ }
+ }
+}
diff --git a/contracts/src/ocr2/aggregator_proxy.cairo b/contracts/src/ocr2/aggregator_proxy.cairo
new file mode 100644
index 0000000..5be3f9d
--- /dev/null
+++ b/contracts/src/ocr2/aggregator_proxy.cairo
@@ -0,0 +1,262 @@
+use plugin::ocr2::aggregator::Round;
+use plugin::ocr2::aggregator::{IAggregator, IAggregatorDispatcher, IAggregatorDispatcherTrait};
+use starknet::ContractAddress;
+
+// TODO: use a generic param for the round_id?
+#[starknet::interface]
+trait IAggregatorProxy {
+ fn latest_round_data(self: @TContractState) -> Round;
+ fn round_data(self: @TContractState, round_id: felt252) -> Round;
+ fn description(self: @TContractState) -> felt252;
+ fn decimals(self: @TContractState) -> u8;
+ fn latest_answer(self: @TContractState) -> u128;
+}
+
+#[starknet::interface]
+trait IAggregatorProxyInternal {
+ fn propose_aggregator(ref self: TContractState, address: ContractAddress);
+ fn confirm_aggregator(ref self: TContractState, address: ContractAddress);
+ fn proposed_latest_round_data(self: @TContractState) -> Round;
+ fn proposed_round_data(self: @TContractState, round_id: felt252) -> Round;
+ fn aggregator(self: @TContractState) -> ContractAddress;
+ fn phase_id(self: @TContractState) -> u128;
+}
+
+#[starknet::contract]
+mod AggregatorProxy {
+ use super::IAggregatorProxy;
+ use super::IAggregatorDispatcher;
+ use super::IAggregatorDispatcherTrait;
+
+ use integer::u128s_from_felt252;
+ use option::OptionTrait;
+ use traits::Into;
+ use traits::TryInto;
+ use zeroable::Zeroable;
+
+ use starknet::ContractAddress;
+ use starknet::ContractAddressIntoFelt252;
+ use starknet::Felt252TryIntoContractAddress;
+ use integer::Felt252TryIntoU128;
+ use starknet::StorageBaseAddress;
+ use starknet::SyscallResult;
+ use integer::U128IntoFelt252;
+ use integer::U128sFromFelt252Result;
+ use starknet::storage_read_syscall;
+ use starknet::storage_write_syscall;
+ use starknet::storage_address_from_base_and_offset;
+ use starknet::class_hash::ClassHash;
+
+ use openzeppelin::access::ownable::OwnableComponent;
+
+ use plugin::ocr2::aggregator::IAggregator;
+ use plugin::ocr2::aggregator::Round;
+ use plugin::libraries::access_control::{AccessControlComponent, IAccessController};
+ use plugin::libraries::access_control::AccessControlComponent::InternalTrait as AccessControlInternalTrait;
+ use plugin::utils::split_felt;
+ use plugin::libraries::type_and_version::{
+ ITypeAndVersion, ITypeAndVersionDispatcher, ITypeAndVersionDispatcherTrait
+ };
+ use plugin::libraries::upgradeable::{Upgradeable, IUpgradeable};
+
+ const SHIFT: felt252 = 0x100000000000000000000000000000000;
+ const MAX_ID: felt252 = 0xffffffffffffffffffffffffffffffff;
+
+ #[derive(Copy, Drop, Serde, starknet::Store)]
+ struct Phase {
+ id: u128,
+ aggregator: ContractAddress
+ }
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent);
+
+ #[abi(embed_v0)]
+ impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl;
+ impl OwnableInternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl AccessControlImpl =
+ AccessControlComponent::AccessControlImpl;
+ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ #[substorage(v0)]
+ access_control: AccessControlComponent::Storage,
+ _current_phase: Phase,
+ _proposed_aggregator: ContractAddress,
+ _phases: LegacyMap
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ AccessControlEvent: AccessControlComponent::Event,
+ }
+
+ // TODO: refactor these events
+ #[event]
+ fn AggregatorProposed(current: ContractAddress, proposed: ContractAddress) {}
+
+ #[event]
+ fn AggregatorConfirmed(previous: ContractAddress, latest: ContractAddress) {}
+
+ #[abi(embed_v0)]
+ impl AggregatorProxyImpl of IAggregatorProxy {
+ fn latest_round_data(self: @ContractState) -> Round {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ let aggregator = IAggregatorDispatcher { contract_address: phase.aggregator };
+ let round = aggregator.latest_round_data();
+
+ Round {
+ round_id: (phase.id.into() * SHIFT) + round.round_id,
+ answer: round.answer,
+ block_num: round.block_num,
+ started_at: round.started_at,
+ updated_at: round.updated_at,
+ }
+ }
+ fn round_data(self: @ContractState, round_id: felt252) -> Round {
+ self._require_read_access();
+ let (phase_id, round_id) = split_felt(round_id);
+ let address = self._phases.read(phase_id);
+ assert(!address.is_zero(), 'aggregator address is 0');
+
+ let aggregator = IAggregatorDispatcher { contract_address: address };
+ let round = aggregator.round_data(round_id);
+
+ Round {
+ round_id: (phase_id.into() * SHIFT) + round.round_id,
+ answer: round.answer,
+ block_num: round.block_num,
+ started_at: round.started_at,
+ updated_at: round.updated_at,
+ }
+ }
+ fn description(self: @ContractState) -> felt252 {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ let aggregator = IAggregatorDispatcher { contract_address: phase.aggregator };
+ aggregator.description()
+ }
+
+ fn decimals(self: @ContractState) -> u8 {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ let aggregator = IAggregatorDispatcher { contract_address: phase.aggregator };
+ aggregator.decimals()
+ }
+
+ fn latest_answer(self: @ContractState) -> u128 {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ let aggregator = IAggregatorDispatcher { contract_address: phase.aggregator };
+ aggregator.latest_answer()
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersion of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ let phase = self._current_phase.read();
+ let aggregator = ITypeAndVersionDispatcher { contract_address: phase.aggregator };
+ aggregator.type_and_version()
+ }
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, owner: ContractAddress, address: ContractAddress) {
+ self.ownable.initializer(owner);
+ self.access_control.initializer();
+ self._set_aggregator(address);
+ }
+
+ // -- Upgradeable --
+
+ #[abi(embed_v0)]
+ impl UpgradeableImpl of IUpgradeable {
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self.ownable.assert_only_owner();
+ Upgradeable::upgrade(new_impl)
+ }
+ }
+
+ //
+
+ #[abi(embed_v0)]
+ impl AggregatorProxyInternal of super::IAggregatorProxyInternal {
+ fn propose_aggregator(ref self: ContractState, address: ContractAddress) {
+ self.ownable.assert_only_owner();
+ assert(!address.is_zero(), 'proposed address is 0');
+ self._proposed_aggregator.write(address);
+
+ let phase = self._current_phase.read();
+ AggregatorProposed(phase.aggregator, address);
+ }
+
+ fn confirm_aggregator(ref self: ContractState, address: ContractAddress) {
+ self.ownable.assert_only_owner();
+ assert(!address.is_zero(), 'confirm address is 0');
+ let phase = self._current_phase.read();
+ let previous = phase.aggregator;
+
+ let proposed_aggregator = self._proposed_aggregator.read();
+ assert(address == proposed_aggregator, 'does not match proposed address');
+ self._proposed_aggregator.write(starknet::contract_address_const::<0>());
+ self._set_aggregator(proposed_aggregator);
+
+ AggregatorConfirmed(previous, address);
+ }
+
+ fn proposed_latest_round_data(self: @ContractState) -> Round {
+ self._require_read_access();
+ let address = self._proposed_aggregator.read();
+ let aggregator = IAggregatorDispatcher { contract_address: address };
+ aggregator.latest_round_data()
+ }
+
+ fn proposed_round_data(self: @ContractState, round_id: felt252) -> Round {
+ self._require_read_access();
+ let address = self._proposed_aggregator.read();
+ let round_id128: u128 = round_id.try_into().unwrap();
+ let aggregator = IAggregatorDispatcher { contract_address: address };
+ aggregator.round_data(round_id128)
+ }
+
+ fn aggregator(self: @ContractState) -> ContractAddress {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ phase.aggregator
+ }
+
+ fn phase_id(self: @ContractState) -> u128 {
+ self._require_read_access();
+ let phase = self._current_phase.read();
+ phase.id
+ }
+ }
+
+ /// Internals
+
+ #[generate_trait]
+ impl StorageImpl of StorageTrait {
+ fn _set_aggregator(ref self: ContractState, address: ContractAddress) {
+ let phase = self._current_phase.read();
+ let new_phase_id = phase.id + 1_u128;
+ self._current_phase.write(Phase { id: new_phase_id, aggregator: address });
+ self._phases.write(new_phase_id, address);
+ }
+
+ fn _require_read_access(self: @ContractState) {
+ let caller = starknet::info::get_caller_address();
+ self.access_control.check_read_access(caller);
+ }
+ }
+}
diff --git a/contracts/src/ocr2/mocks.cairo b/contracts/src/ocr2/mocks.cairo
new file mode 100644
index 0000000..16f9b33
--- /dev/null
+++ b/contracts/src/ocr2/mocks.cairo
@@ -0,0 +1 @@
+mod mock_aggregator;
diff --git a/contracts/src/ocr2/mocks/mock_aggregator.cairo b/contracts/src/ocr2/mocks/mock_aggregator.cairo
new file mode 100644
index 0000000..6ffa07b
--- /dev/null
+++ b/contracts/src/ocr2/mocks/mock_aggregator.cairo
@@ -0,0 +1,127 @@
+#[starknet::interface]
+trait IMockAggregator {
+ fn set_latest_round_data(
+ ref self: TContractState,
+ answer: u128,
+ block_num: u64,
+ observation_timestamp: u64,
+ transmission_timestamp: u64
+ );
+}
+
+#[starknet::contract]
+mod MockAggregator {
+ use array::ArrayTrait;
+ use starknet::contract_address_const;
+ use traits::Into;
+
+ use plugin::ocr2::aggregator::IAggregator;
+ use plugin::ocr2::aggregator::Aggregator::{Transmission, NewTransmission};
+ use plugin::ocr2::aggregator::Round;
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+
+ #[event]
+ use plugin::ocr2::aggregator::Aggregator::Event;
+
+ #[storage]
+ struct Storage {
+ _transmissions: LegacyMap,
+ _latest_aggregator_round_id: u128,
+ _decimals: u8
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, decimals: u8) {
+ self._decimals.write(decimals);
+ }
+
+ #[abi(embed_v0)]
+ impl MockImpl of super::IMockAggregator {
+ fn set_latest_round_data(
+ ref self: ContractState,
+ answer: u128,
+ block_num: u64,
+ observation_timestamp: u64,
+ transmission_timestamp: u64
+ ) {
+ let new_round_id = self._latest_aggregator_round_id.read() + 1_u128;
+ self
+ ._transmissions
+ .write(
+ new_round_id,
+ Transmission {
+ answer: answer,
+ block_num: block_num,
+ observation_timestamp: observation_timestamp,
+ transmission_timestamp: transmission_timestamp
+ }
+ );
+
+ let mut observations = ArrayTrait::new();
+ observations.append(2_u128);
+ observations.append(3_u128);
+
+ self._latest_aggregator_round_id.write(new_round_id);
+
+ self
+ .emit(
+ Event::NewTransmission(
+ NewTransmission {
+ round_id: new_round_id,
+ answer: answer,
+ transmitter: contract_address_const::<42>(),
+ observation_timestamp: observation_timestamp,
+ observers: 3,
+ observations: observations,
+ juels_per_fee_coin: 18_u128,
+ gas_price: 1_u128,
+ config_digest: 777,
+ epoch_and_round: 20_u64,
+ reimbursement: 100_u128
+ }
+ )
+ );
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersionImpl of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ 'mock_aggregator.cairo 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl Aggregator of IAggregator {
+ fn round_data(self: @ContractState, round_id: u128) -> Round {
+ panic_with_felt252('unimplemented')
+ }
+
+ fn latest_round_data(self: @ContractState) -> Round {
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let transmission = self._transmissions.read(latest_round_id);
+
+ Round {
+ round_id: latest_round_id.into(),
+ answer: transmission.answer,
+ block_num: transmission.block_num,
+ started_at: transmission.observation_timestamp,
+ updated_at: transmission.transmission_timestamp
+ }
+ }
+
+ fn decimals(self: @ContractState) -> u8 {
+ self._decimals.read()
+ }
+
+ fn description(self: @ContractState) -> felt252 {
+ 'mock'
+ }
+
+ fn latest_answer(self: @ContractState) -> u128 {
+ let latest_round_id = self._latest_aggregator_round_id.read();
+ let transmission = self._transmissions.read(latest_round_id);
+ transmission.answer
+ }
+ }
+}
diff --git a/contracts/src/plugin/cairo/access/IAccessController.cairo b/contracts/src/plugin/cairo/access/IAccessController.cairo
deleted file mode 100644
index b6ba969..0000000
--- a/contracts/src/plugin/cairo/access/IAccessController.cairo
+++ /dev/null
@@ -1,10 +0,0 @@
-%lang starknet
-
-@contract_interface
-namespace IAccessController {
- func has_access(user: felt, data_len: felt, data: felt*) -> (bool: felt) {
- }
-
- func check_access(user: felt) {
- }
-}
diff --git a/contracts/src/plugin/cairo/access/SimpleReadAccessController/library.cairo b/contracts/src/plugin/cairo/access/SimpleReadAccessController/library.cairo
deleted file mode 100644
index b324a45..0000000
--- a/contracts/src/plugin/cairo/access/SimpleReadAccessController/library.cairo
+++ /dev/null
@@ -1,63 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.alloc import alloc
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.starknet.common.syscalls import get_tx_info
-from starkware.cairo.common.bool import TRUE, FALSE
-
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- SimpleWriteAccessController,
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-
-namespace SimpleReadAccessController {
- func initialize{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner_address: felt
- ) {
- SimpleWriteAccessController.initialize(owner_address);
- return ();
- }
-
- // Gives access to:
- // - any externally owned account (note that offchain actors can always read
- // any contract storage regardless of onchain access control measures, so this
- // does not weaken the access control while improving usability)
- // - accounts explicitly added to an access list
- func has_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- user: felt, data_len: felt, data: felt*
- ) -> (bool: felt) {
- let (has_access) = SimpleWriteAccessController.has_access(user, data_len, data);
- if (has_access == TRUE) {
- return (TRUE,);
- }
-
- // NOTICE: access is granted to direct calls, to enable off-chain reads.
- if (user == 0) {
- return (TRUE,);
- }
-
- return (FALSE,);
- }
-
- // TODO: remove when starkware adds get_class_hash_at
- func check_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- alloc_locals;
-
- let empty_data_len = 0;
- let (empty_data) = alloc();
-
- let (bool) = SimpleReadAccessController.has_access(user, empty_data_len, empty_data);
- with_attr error_message("SimpleReadAccessController: address does not have access") {
- assert bool = TRUE;
- }
-
- return ();
- }
-}
diff --git a/contracts/src/plugin/cairo/access/SimpleReadAccessController/simple_read_access_controller.cairo b/contracts/src/plugin/cairo/access/SimpleReadAccessController/simple_read_access_controller.cairo
deleted file mode 100644
index c30505a..0000000
--- a/contracts/src/plugin/cairo/access/SimpleReadAccessController/simple_read_access_controller.cairo
+++ /dev/null
@@ -1,39 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-
-from plugin.cairo.access.SimpleReadAccessController.library import SimpleReadAccessController
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner_address: felt
-) {
- SimpleReadAccessController.initialize(owner_address);
- return ();
-}
-
-// implements IAccessController
-@view
-func has_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- user: felt, data_len: felt, data: felt*
-) -> (bool: felt) {
- let (has_access) = SimpleReadAccessController.has_access(user, data_len, data);
- return (has_access,);
-}
-
-// implements IAccessController
-@view
-func check_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- SimpleReadAccessController.check_access(user);
- return ();
-}
diff --git a/contracts/src/plugin/cairo/access/SimpleWriteAccessController/library.cairo b/contracts/src/plugin/cairo/access/SimpleWriteAccessController/library.cairo
deleted file mode 100644
index 0d09f83..0000000
--- a/contracts/src/plugin/cairo/access/SimpleWriteAccessController/library.cairo
+++ /dev/null
@@ -1,158 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.alloc import alloc
-from starkware.cairo.common.bool import TRUE, FALSE
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-
-from plugin.cairo.access.ownable import Ownable
-
-@event
-func AddedAccess(user: felt) {
-}
-
-@event
-func RemovedAccess(user: felt) {
-}
-
-@event
-func CheckAccessEnabled() {
-}
-
-@event
-func CheckAccessDisabled() {
-}
-
-@storage_var
-func SimpleWriteAccessController_check_enabled() -> (checkEnabled: felt) {
-}
-
-@storage_var
-func SimpleWriteAccessController_access_list(address: felt) -> (bool: felt) {
-}
-
-// --- Ownership ---
-
-@view
-func owner{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}() -> (owner: felt) {
- let (owner) = Ownable.get_owner();
- return (owner=owner);
-}
-
-@view
-func proposed_owner{pedersen_ptr: HashBuiltin*, syscall_ptr: felt*, range_check_ptr}() -> (
- proposed_owner: felt
-) {
- let (proposed_owner) = Ownable.get_proposed_owner();
- return (proposed_owner=proposed_owner);
-}
-
-@external
-func transfer_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- new_owner: felt
-) -> () {
- return Ownable.transfer_ownership(new_owner);
-}
-
-@external
-func accept_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- return Ownable.accept_ownership();
-}
-
-// --- AC ---
-
-// Adds an address to the access list
-@external
-func add_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- Ownable.assert_only_owner();
- let (has_access) = SimpleWriteAccessController_access_list.read(user);
- if (has_access == FALSE) {
- SimpleWriteAccessController_access_list.write(user, TRUE);
- AddedAccess.emit(user);
- return ();
- }
-
- return ();
-}
-
-// Removes an address from the access list
-@external
-func remove_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- Ownable.assert_only_owner();
- let (has_access) = SimpleWriteAccessController_access_list.read(user);
- if (has_access == TRUE) {
- SimpleWriteAccessController_access_list.write(user, FALSE);
- RemovedAccess.emit(user);
- return ();
- }
-
- return ();
-}
-
-// Makes the access check enforced
-@external
-func enable_access_check{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- Ownable.assert_only_owner();
- let (check_enabled) = SimpleWriteAccessController_check_enabled.read();
- if (check_enabled == FALSE) {
- SimpleWriteAccessController_check_enabled.write(TRUE);
- CheckAccessEnabled.emit();
- return ();
- }
-
- return ();
-}
-
-// makes the access check unenforced
-@external
-func disable_access_check{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- Ownable.assert_only_owner();
- let (check_enabled) = SimpleWriteAccessController_check_enabled.read();
- if (check_enabled == TRUE) {
- SimpleWriteAccessController_check_enabled.write(FALSE);
- CheckAccessDisabled.emit();
- return ();
- }
-
- return ();
-}
-
-namespace SimpleWriteAccessController {
- func initialize{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner_address: felt
- ) {
- Ownable.initializer(owner_address);
- SimpleWriteAccessController_check_enabled.write(TRUE);
-
- return ();
- }
-
- func has_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- user: felt, data_len: felt, data: felt*
- ) -> (bool: felt) {
- let (has_access) = SimpleWriteAccessController_access_list.read(user);
- if (has_access == TRUE) {
- return (TRUE,);
- }
-
- let (check_enabled) = SimpleWriteAccessController_check_enabled.read();
- if (check_enabled == FALSE) {
- return (TRUE,);
- }
-
- return (FALSE,);
- }
-
- func check_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- alloc_locals;
-
- let empty_data_len = 0;
- let (empty_data) = alloc();
-
- let (bool) = SimpleWriteAccessController.has_access(user, empty_data_len, empty_data);
- with_attr error_message("SimpleWriteAccessController: address does not have access") {
- assert bool = TRUE;
- }
-
- return ();
- }
-}
diff --git a/contracts/src/plugin/cairo/access/SimpleWriteAccessController/simple_write_access_controller.cairo b/contracts/src/plugin/cairo/access/SimpleWriteAccessController/simple_write_access_controller.cairo
deleted file mode 100644
index 6571cf0..0000000
--- a/contracts/src/plugin/cairo/access/SimpleWriteAccessController/simple_write_access_controller.cairo
+++ /dev/null
@@ -1,29 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-
-from plugin.cairo.access.SimpleWriteAccessController.library import SimpleWriteAccessController
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner_address: felt
-) {
- SimpleWriteAccessController.initialize(owner_address);
- return ();
-}
-
-// implements IAccessController
-@view
-func has_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- user: felt, data_len: felt, data: felt*
-) -> (bool: felt) {
- let (has_access) = SimpleWriteAccessController.has_access(user, data_len, data);
- return (has_access,);
-}
-
-// implements IAccessController
-@view
-func check_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- SimpleWriteAccessController.check_access(user);
- return ();
-}
diff --git a/contracts/src/plugin/cairo/access/ownable.cairo b/contracts/src/plugin/cairo/access/ownable.cairo
deleted file mode 100644
index fcc3c21..0000000
--- a/contracts/src/plugin/cairo/access/ownable.cairo
+++ /dev/null
@@ -1,117 +0,0 @@
-// Equivalent to openzeppelin/Ownable except it's a two step process to transfer ownership.
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.starknet.common.syscalls import get_caller_address
-from starkware.cairo.common.math import assert_not_zero
-
-//
-// Events
-//
-
-@event
-func OwnershipTransferred(previousOwner: felt, newOwner: felt) {
-}
-
-@event
-func OwnershipTransferRequested(from_address: felt, to: felt) {
-}
-
-//
-// Storage
-//
-
-@storage_var
-func Ownable_owner() -> (owner: felt) {
-}
-
-@storage_var
-func Ownable_proposed_owner() -> (proposed_owner: felt) {
-}
-
-namespace Ownable {
- //
- // Constructor
- //
- func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) {
- with_attr error_message("Ownable: cannot transfer to zero address") {
- assert_not_zero(owner);
- }
- _accept_ownership_transfer(owner);
- return ();
- }
-
- func assert_only_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (owner) = Ownable_owner.read();
- let (caller) = get_caller_address();
- // caller is the zero address should not be possible anymore with introduction of fees
- with_attr error_message("Ownable: caller is the zero address") {
- assert_not_zero(caller);
- }
- with_attr error_message("Ownable: caller is not the owner") {
- assert owner = caller;
- }
- return ();
- }
-
- func get_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- owner: felt
- ) {
- let (owner) = Ownable_owner.read();
- return (owner=owner);
- }
-
- func get_proposed_owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- proposed_owner: felt
- ) {
- let (proposed_owner) = Ownable_proposed_owner.read();
- return (proposed_owner=proposed_owner);
- }
-
- func transfer_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- new_owner: felt
- ) -> () {
- with_attr error_message("Ownable: cannot transfer to zero address") {
- assert_not_zero(new_owner);
- }
- assert_only_owner();
- Ownable_proposed_owner.write(new_owner);
- let (previous_owner: felt) = Ownable_owner.read();
- OwnershipTransferRequested.emit(previous_owner, new_owner);
- return ();
- }
-
- func accept_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (proposed_owner) = Ownable_proposed_owner.read();
- let (caller) = get_caller_address();
- // caller cannot be zero address to avoid overwriting owner when proposed_owner is not set
- with_attr error_message("Ownable: caller is the zero address") {
- assert_not_zero(caller);
- }
- with_attr error_message("Ownable: caller is not the proposed owner") {
- assert proposed_owner = caller;
- }
- _accept_ownership_transfer(proposed_owner);
- return ();
- }
-
- func renounce_ownership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- assert_only_owner();
- _accept_ownership_transfer(0);
- return ();
- }
-
- //
- // Internal
- //
-
- func _accept_ownership_transfer{
- syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr
- }(new_owner: felt) {
- let (previous_owner: felt) = Ownable_owner.read();
- Ownable_owner.write(new_owner);
- Ownable_proposed_owner.write(0);
- OwnershipTransferred.emit(previous_owner, new_owner);
- return ();
- }
-}
diff --git a/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/library.cairo b/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/library.cairo
deleted file mode 100644
index 8df7c39..0000000
--- a/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/library.cairo
+++ /dev/null
@@ -1,269 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.starknet.common.syscalls import (
- get_block_timestamp,
- get_caller_address,
- get_block_number,
-)
-from starkware.cairo.common.math import assert_not_zero, assert_nn_le, assert_lt_felt
-from starkware.cairo.common.math_cmp import is_le
-from starkware.cairo.common.bool import TRUE
-
-from plugin.cairo.utils import assert_boolean
-from plugin.cairo.ocr2.IAggregator import Round, AnswerUpdated, NewRound
-from plugin.cairo.access.SimpleReadAccessController.library import SimpleReadAccessController
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-from plugin.cairo.access.ownable import Ownable
-
-const ETH_ADDRESS_BOUND = 2 ** 160;
-
-@event
-func RoundUpdated(status: felt, updated_at: felt) {
-}
-
-@event
-func UpdateIgnored(
- latest_status: felt, latest_timestamp: felt, incoming_status: felt, incoming_timestamp: felt
-) {
-}
-
-@event
-func L1SenderTransferred(from_addr: felt, to_addr: felt) {
-}
-
-@storage_var
-func SequencerUptimeFeed_l1_sender() -> (address: felt) {
-}
-
-@storage_var
-func SequencerUptimeFeed_rounds(id: felt, field: felt) -> (res: felt) {
-}
-
-@storage_var
-func SequencerUptimeFeed_latest_round_id() -> (res: felt) {
-}
-
-func require_l1_sender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- address: felt
-) {
- let (l1_sender) = SequencerUptimeFeed_l1_sender.read();
- with_attr error_message("SequencerUptimeFeed: invalid sender") {
- assert l1_sender = address;
- }
-
- return ();
-}
-
-func require_valid_round_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) {
- let (latest_round_id) = SequencerUptimeFeed_latest_round_id.read();
-
- with_attr error_message("SequencerUptimeFeed: invalid round_id") {
- assert_not_zero(round_id);
- assert_nn_le(round_id, latest_round_id);
- }
-
- return ();
-}
-
-func require_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (address) = get_caller_address();
- SimpleReadAccessController.check_access(address);
-
- return ();
-}
-
-// TODO: make overridable in the future
-@external
-func set_l1_sender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(address: felt) {
- Ownable.assert_only_owner();
-
- with_attr error_message("SequencerUptimeFeed: L1 sender address out of range") {
- assert_lt_felt(address, ETH_ADDRESS_BOUND);
- }
-
- with_attr error_message("SequencerUptimeFeed: L1 sender address can not be zero") {
- assert_not_zero(address);
- }
- _set_l1_sender(address);
-
- return ();
-}
-
-@view
-func l1_sender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- address: felt
-) {
- let (address) = SequencerUptimeFeed_l1_sender.read();
- return (address,);
-}
-
-namespace SequencerUptimeFeed {
- func initialize{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- initial_status: felt, owner_address: felt
- ) {
- with_attr error_message("SequencerUptimeFeed: value isn't a boolean") {
- assert_boolean(initial_status);
- }
-
- SimpleReadAccessController.initialize(owner_address);
-
- let round_id = 1;
- let (timestamp) = get_block_timestamp();
- _record_round(round_id, initial_status, timestamp);
-
- return ();
- }
-
- func update_status{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- from_address: felt, status: felt, timestamp: felt
- ) {
- alloc_locals;
- require_l1_sender(from_address);
- with_attr error_message("SequencerUptimeFeed: value isn't a boolean") {
- assert_boolean(status);
- }
-
- let (latest_round_id) = SequencerUptimeFeed_latest_round_id.read();
- let (latest_started_at) = SequencerUptimeFeed_rounds.read(
- latest_round_id, Round.started_at
- );
- let (local latest_status) = SequencerUptimeFeed_rounds.read(latest_round_id, Round.answer);
-
- let lt = is_le(timestamp, latest_started_at - 1); // timestamp < latest_started_at
- if (lt == TRUE) {
- UpdateIgnored.emit(latest_status, latest_started_at, status, timestamp);
- return ();
- }
-
- if (latest_status == status) {
- _update_round(latest_round_id, status);
- } else {
- let round_id = latest_round_id + 1;
- _record_round(round_id, status, timestamp);
- }
-
- return ();
- }
-
- func latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
- ) {
- require_access();
-
- let (latest_round_id) = SequencerUptimeFeed_latest_round_id.read();
- let (latest_round) = SequencerUptimeFeed.round_data(latest_round_id);
-
- return (latest_round,);
- }
-
- func round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
- ) -> (res: Round) {
- require_access();
- require_valid_round_id(round_id);
-
- let (round) = _get_round(round_id);
- return (round,);
- }
-
- func description{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- description: felt
- ) {
- return ('L2 Sequencer Uptime Status Feed',);
- }
-
- func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
- ) {
- return (0,);
- }
-
- func type_and_version{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- meta: felt
- ) {
- const meta = 'SequencerUptimeFeed 1.0.0';
- return (meta,);
- }
-}
-
-func _set_round{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt, value: Round
-) {
- SequencerUptimeFeed_rounds.write(id=round_id, field=Round.answer, value=value.answer);
- SequencerUptimeFeed_rounds.write(id=round_id, field=Round.block_num, value=value.block_num);
- SequencerUptimeFeed_rounds.write(id=round_id, field=Round.started_at, value=value.started_at);
- SequencerUptimeFeed_rounds.write(id=round_id, field=Round.updated_at, value=value.updated_at);
-
- return ();
-}
-
-func _get_round{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) -> (round: Round) {
- let (answer) = SequencerUptimeFeed_rounds.read(id=round_id, field=Round.answer);
- let (block_num) = SequencerUptimeFeed_rounds.read(id=round_id, field=Round.block_num);
- let (started_at) = SequencerUptimeFeed_rounds.read(id=round_id, field=Round.started_at);
- let (updated_at) = SequencerUptimeFeed_rounds.read(id=round_id, field=Round.updated_at);
-
- return (Round(round_id, answer, block_num, started_at, updated_at),);
-}
-
-func _set_l1_sender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- address: felt
-) {
- let (old_address) = SequencerUptimeFeed_l1_sender.read();
-
- if (old_address != address) {
- SequencerUptimeFeed_l1_sender.write(address);
- L1SenderTransferred.emit(old_address, address);
- return ();
- }
-
- return ();
-}
-
-func _record_round{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt, status: felt, timestamp: felt
-) {
- SequencerUptimeFeed_latest_round_id.write(round_id);
-
- let (block_num) = get_block_number();
- let (updated_at) = get_block_timestamp();
-
- let round = Round(
- round_id=round_id,
- answer=status,
- block_num=block_num,
- started_at=timestamp,
- updated_at=updated_at,
- );
- _set_round(round_id, round);
-
- let (sender) = get_caller_address();
- NewRound.emit(round_id=round_id, started_by=sender, started_at=timestamp);
- AnswerUpdated.emit(status, round_id, timestamp);
-
- return ();
-}
-
-func _update_round{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt, status: felt
-) {
- let (updated_at) = get_block_timestamp();
- SequencerUptimeFeed_rounds.write(round_id, Round.updated_at, updated_at);
-
- RoundUpdated.emit(status, updated_at);
- return ();
-}
diff --git a/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/sequencer_uptime_feed.cairo b/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/sequencer_uptime_feed.cairo
deleted file mode 100644
index aca4389..0000000
--- a/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/sequencer_uptime_feed.cairo
+++ /dev/null
@@ -1,99 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-
-from plugin.cairo.access.SimpleReadAccessController.library import SimpleReadAccessController
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-from plugin.cairo.ocr2.IAggregator import Round
-from plugin.cairo.emergency.SequencerUptimeFeed.library import (
- SequencerUptimeFeed,
- set_l1_sender,
- l1_sender,
-)
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- initial_status: felt, owner_address: felt
-) {
- SequencerUptimeFeed.initialize(initial_status, owner_address);
- return ();
-}
-
-// implements IAggregator
-@l1_handler
-func update_status{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- from_address: felt, status: felt, timestamp: felt
-) {
- SequencerUptimeFeed.update_status(from_address, status, timestamp);
- return ();
-}
-
-// implements IAggregator
-@view
-func latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- let (latest_round) = SequencerUptimeFeed.latest_round_data();
- return (latest_round,);
-}
-
-// implements IAggregator
-@view
-func round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) -> (res: Round) {
- let (round) = SequencerUptimeFeed.round_data(round_id);
- return (round,);
-}
-
-// implements IAggregator
-@view
-func description{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- description: felt
-) {
- let (description) = SequencerUptimeFeed.description();
- return (description,);
-}
-
-// implements IAggregator
-@view
-func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- let (decimals) = SequencerUptimeFeed.decimals();
- return (decimals,);
-}
-
-// implements IAggregator
-@view
-func type_and_version{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- meta: felt
-) {
- let (meta) = SequencerUptimeFeed.type_and_version();
- return (meta,);
-}
-
-// implements IAccessController
-@view
-func has_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- user: felt, data_len: felt, data: felt*
-) -> (bool: felt) {
- let (has_access) = SimpleReadAccessController.has_access(user, data_len, data);
- return (has_access,);
-}
-
-// implements IAccessController
-@view
-func check_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(user: felt) {
- SimpleReadAccessController.check_access(user);
- return ();
-}
diff --git a/contracts/src/plugin/cairo/example/Aggregator_consumer.cairo b/contracts/src/plugin/cairo/example/Aggregator_consumer.cairo
deleted file mode 100644
index aae9031..0000000
--- a/contracts/src/plugin/cairo/example/Aggregator_consumer.cairo
+++ /dev/null
@@ -1,32 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from plugin.cairo.ocr2.IAggregator import IAggregator, Round
-
-@storage_var
-func AggregatorConsumer_ocr_address() -> (address: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(address: felt) {
- AggregatorConsumer_ocr_address.write(address);
- return ();
-}
-
-@view
-func readLatestRound{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- let (address) = AggregatorConsumer_ocr_address.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=address);
- return (round,);
-}
-
-@view
-func readDecimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- let (address) = AggregatorConsumer_ocr_address.read();
- let (decimals) = IAggregator.decimals(contract_address=address);
- return (decimals,);
-}
diff --git a/contracts/src/plugin/cairo/introspection/ITypeAndVersion.cairo b/contracts/src/plugin/cairo/introspection/ITypeAndVersion.cairo
deleted file mode 100644
index d64f26b..0000000
--- a/contracts/src/plugin/cairo/introspection/ITypeAndVersion.cairo
+++ /dev/null
@@ -1,7 +0,0 @@
-%lang starknet
-
-@contract_interface
-namespace ITypeAndVersion {
- func type_and_version() -> (meta: felt) {
- }
-}
diff --git a/contracts/src/plugin/cairo/ocr2/IAggregator.cairo b/contracts/src/plugin/cairo/ocr2/IAggregator.cairo
deleted file mode 100644
index 34e7248..0000000
--- a/contracts/src/plugin/cairo/ocr2/IAggregator.cairo
+++ /dev/null
@@ -1,52 +0,0 @@
-%lang starknet
-
-struct Round {
- round_id: felt,
- answer: felt,
- block_num: felt,
- started_at: felt,
- updated_at: felt,
-}
-
-@event
-func NewTransmission(
- round_id: felt,
- answer: felt,
- transmitter: felt,
- observation_timestamp: felt,
- observers: felt,
- observations_len: felt,
- observations: felt*,
- juels_per_fee_coin: felt,
- gas_price: felt,
- config_digest: felt,
- epoch_and_round: felt,
- reimbursement: felt,
-) {
-}
-
-@event
-func AnswerUpdated(current: felt, round_id: felt, timestamp: felt) {
-}
-
-@event
-func NewRound(round_id: felt, started_by: felt, started_at: felt) {
-}
-
-@contract_interface
-namespace IAggregator {
- func latest_round_data() -> (round: Round) {
- }
-
- func round_data(round_id: felt) -> (round: Round) {
- }
-
- func description() -> (description: felt) {
- }
-
- func decimals() -> (decimals: felt) {
- }
-
- func type_and_version() -> (meta: felt) {
- }
-}
diff --git a/contracts/src/plugin/cairo/ocr2/aggregator.cairo b/contracts/src/plugin/cairo/ocr2/aggregator.cairo
deleted file mode 100644
index 7a066b9..0000000
--- a/contracts/src/plugin/cairo/ocr2/aggregator.cairo
+++ /dev/null
@@ -1,1232 +0,0 @@
-// amarna: disable=arithmetic-div,arithmetic-sub,arithmetic-mul,arithmetic-add
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin
-from starkware.cairo.common.alloc import alloc
-from starkware.cairo.common.registers import get_fp_and_pc
-from starkware.cairo.common.hash_state import (
- hash_init,
- hash_finalize,
- hash_update,
- hash_update_single,
-)
-from starkware.cairo.common.signature import verify_ecdsa_signature
-from starkware.cairo.common.bitwise import bitwise_and
-from starkware.cairo.common.bool import TRUE
-from starkware.cairo.common.math import (
- abs_value,
- assert_le_felt,
- assert_lt,
- assert_not_zero,
- assert_not_equal,
- assert_nn_le,
- assert_nn,
- assert_in_range,
- unsigned_div_rem,
-)
-from starkware.cairo.common.math_cmp import is_nn
-from starkware.cairo.common.pow import pow
-from starkware.cairo.common.uint256 import (
- Uint256,
- uint256_sub,
- uint256_lt,
- uint256_le,
- uint256_check,
-)
-
-from starkware.starknet.common.syscalls import (
- get_caller_address,
- get_contract_address,
- get_block_timestamp,
- get_block_number,
- get_tx_info,
-)
-
-from openzeppelin.utils.constants.library import UINT8_MAX
-
-from openzeppelin.token.erc20.IERC20 import IERC20
-
-from plugin.cairo.access.IAccessController import IAccessController
-
-from plugin.cairo.utils import felt_to_uint256, uint256_to_felt
-
-from plugin.cairo.access.ownable import Ownable
-
-from plugin.cairo.access.SimpleReadAccessController.library import SimpleReadAccessController
-
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-
-from plugin.cairo.ocr2.IAggregator import NewTransmission, Round
-
-// ---
-
-const MAX_ORACLES = 31;
-
-const GIGA = 10 ** 9;
-
-const UINT32_MAX = (2 ** 32) - 1;
-const INT128_MAX = (2 ** (128 - 1)) - 1;
-
-// Maximum number of faulty oracles
-@storage_var
-func Aggregator_f() -> (f: felt) {
-}
-
-@storage_var
-func Aggregator_latest_epoch_and_round() -> (res: felt) {
-}
-
-@storage_var
-func Aggregator_latest_aggregator_round_id() -> (round_id: felt) {
-}
-
-using Range = (min: felt, max: felt);
-
-@storage_var
-func Aggregator_answer_range() -> (range: Range) {
-}
-
-@storage_var
-func Aggregator_decimals() -> (decimals: felt) {
-}
-
-@storage_var
-func Aggregator_description() -> (description: felt) {
-}
-
-//
-
-@storage_var
-func Aggregator_latest_config_block_number() -> (block: felt) {
-}
-
-@storage_var
-func Aggregator_config_count() -> (count: felt) {
-}
-
-@storage_var
-func Aggregator_latest_config_digest() -> (digest: felt) {
-}
-
-@storage_var
-func Aggregator_oracles_len() -> (len: felt) {
-}
-
-// TODO: should we pack into (index, payment) = split_felt()? index is u8, payment is u128
-struct Oracle {
- index: felt,
-
- // entire supply of PLI always fits into u96, so felt is safe to use
- payment_juels: felt,
-}
-
-@storage_var
-func Aggregator_transmitters(pkey: felt) -> (index: Oracle) {
-}
-
-@storage_var
-func Aggregator_signers(pkey: felt) -> (index: felt) {
-}
-
-@storage_var
-func Aggregator_signers_list(index: felt) -> (pkey: felt) {
-}
-
-@storage_var
-func Aggregator_transmitters_list(index: felt) -> (pkey: felt) {
-}
-
-@storage_var
-func reward_from_aggregator_round_id_(index: felt) -> (round_id: felt) {
-}
-
-// ---
-
-struct Transmission {
- answer: felt,
- block_num: felt,
- observation_timestamp: felt,
- transmission_timestamp: felt,
-}
-
-@storage_var
-func Aggregator_transmissions(round_id: felt) -> (transmission: Transmission) {
-}
-
-// ---
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner: felt,
- link: felt,
- min_answer: felt,
- max_answer: felt,
- billing_access_controller: felt,
- decimals: felt,
- description: felt,
-) {
- Ownable.initializer(owner);
- SimpleReadAccessController.initialize(owner); // This also calls Ownable.initializer
- Aggregator_link_token.write(link);
- Aggregator_billing_access_controller.write(billing_access_controller);
-
- assert_lt(min_answer, max_answer);
- let range: Range = (min_answer, max_answer);
- Aggregator_answer_range.write(range);
-
- with_attr error_message("Aggregator: decimals are negative or exceed 2^8") {
- assert_nn_le(decimals, UINT8_MAX);
- }
- Aggregator_decimals.write(decimals);
- Aggregator_description.write(description);
- return ();
-}
-
-// --- Validation ---
-
-// NOTE: Currently unimplemented:
-// - Can't set a gas limit on the validator call
-// - Can't catch errors in calls so validation could block submission
-
-// --- Configuration
-
-@event
-func ConfigSet(
- previous_config_block_number: felt,
- latest_config_digest: felt,
- config_count: felt,
- oracles_len: felt,
- oracles: OracleConfig*,
- f: felt,
- onchain_config_len: felt,
- onchain_config: felt*,
- offchain_config_version: felt,
- offchain_config_len: felt,
- offchain_config: felt*,
-) {
-}
-
-struct OracleConfig {
- signer: felt,
- transmitter: felt,
-}
-
-struct OnchainConfig {
- version: felt,
- min_answer: felt,
- max_answer: felt,
-}
-
-@external
-func set_config{
- syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr
-}(
- oracles_len: felt,
- oracles: OracleConfig*,
- f: felt,
- onchain_config_len: felt,
- onchain_config: felt*,
- offchain_config_version: felt,
- offchain_config_len: felt,
- offchain_config: felt*,
-) -> (digest: felt) {
- alloc_locals;
- Ownable.assert_only_owner();
-
- assert_nn_le(oracles_len, MAX_ORACLES); // oracles_len <= MAX_ORACLES
- assert_lt(3 * f, oracles_len); // 3 * f < oracles_len
- assert_nn(f); // f is positive
-
- // Notice: onchain_config is always zero since we don't allow configuring it yet after deployment.
- // The contract still computes the onchain_config while digesting the config using min/maxAnswer set on construction.
- with_attr error_message("Aggregator: onchain_config must be empty") {
- assert onchain_config_len = 0;
- }
-
- let (answer_range: Range) = Aggregator_answer_range.read();
- local computed_onchain_config: OnchainConfig = OnchainConfig(
- version=1, min_answer=answer_range.min, max_answer=answer_range.max
- );
- // cast to felt* and use OnchainConfig.SIZE as len
- let (__fp__, _) = get_fp_and_pc();
- let onchain_config = cast(&computed_onchain_config, felt*);
-
- // pay out existing oracles
- pay_oracles();
-
- // remove old signers/transmitters
- let (len) = Aggregator_oracles_len.read();
- remove_oracles(len);
-
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
-
- // add new oracles (also sets oracle_len_)
- add_oracles(oracles, 0, oracles_len, latest_round_id);
-
- Aggregator_f.write(f);
- let (block_num: felt) = get_block_number();
- let (prev_block_num) = Aggregator_latest_config_block_number.read();
- Aggregator_latest_config_block_number.write(block_num);
- // update config count
- let (config_count) = Aggregator_config_count.read();
- let config_count = config_count + 1;
- Aggregator_config_count.write(config_count);
- // calculate and store config digest
- let (contract_address) = get_contract_address();
- let (tx_info) = get_tx_info();
- let (digest) = config_digest_from_data(
- tx_info.chain_id,
- contract_address,
- config_count,
- oracles_len,
- oracles,
- f,
- OnchainConfig.SIZE,
- onchain_config,
- offchain_config_version,
- offchain_config_len,
- offchain_config,
- );
- Aggregator_latest_config_digest.write(digest);
-
- // reset epoch & round
- Aggregator_latest_epoch_and_round.write(0);
-
- ConfigSet.emit(
- previous_config_block_number=prev_block_num,
- latest_config_digest=digest,
- config_count=config_count,
- oracles_len=oracles_len,
- oracles=oracles,
- f=f,
- onchain_config_len=OnchainConfig.SIZE,
- onchain_config=onchain_config,
- offchain_config_version=offchain_config_version,
- offchain_config_len=offchain_config_len,
- offchain_config=offchain_config,
- );
-
- return (digest,);
-}
-
-func remove_oracles{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(n: felt) {
- if (n == 0) {
- Aggregator_oracles_len.write(0);
- return ();
- }
-
- // delete oracle from all maps
- let (signer) = Aggregator_signers_list.read(n);
- Aggregator_signers.write(signer, 0);
-
- let (transmitter) = Aggregator_transmitters_list.read(n);
- Aggregator_transmitters.write(transmitter, Oracle(index=0, payment_juels=0));
-
- return remove_oracles(n - 1);
-}
-
-func add_oracles{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- oracles: OracleConfig*, index: felt, len: felt, latest_round_id: felt
-) {
- if (len == 0) {
- Aggregator_oracles_len.write(index);
- return ();
- }
-
- // NOTE: index should start with 1 here because storage is 0-initialized.
- // That way signers(pkey) => 0 indicates "not present"
- let index = index + 1;
-
- // Check for duplicates
- let (existing_signer) = Aggregator_signers.read(oracles.signer);
- with_attr error_message("Aggregator: repeated signer") {
- assert existing_signer = 0;
- }
-
- let (existing_transmitter: Oracle) = Aggregator_transmitters.read(oracles.transmitter);
- with_attr error_message("Aggregator: repeated transmitter") {
- assert existing_transmitter.index = 0;
- }
-
- Aggregator_signers.write(oracles.signer, index);
- Aggregator_signers_list.write(index, oracles.signer);
-
- Aggregator_transmitters.write(oracles.transmitter, Oracle(index=index, payment_juels=0));
- Aggregator_transmitters_list.write(index, oracles.transmitter);
-
- reward_from_aggregator_round_id_.write(index, latest_round_id);
-
- return add_oracles(oracles + OracleConfig.SIZE, index, len - 1, latest_round_id);
-}
-
-const DIGEST_MASK = 2 ** (252 - 12) - 1;
-const PREFIX = 4 * 2 ** (252 - 12);
-
-func config_digest_from_data{pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*}(
- chain_id: felt,
- contract_address: felt,
- config_count: felt,
- oracles_len: felt,
- oracles: OracleConfig*,
- f: felt,
- onchain_config_len: felt,
- onchain_config: felt*,
- offchain_config_version: felt,
- offchain_config_len: felt,
- offchain_config: felt*,
-) -> (hash: felt) {
- let hash_ptr = pedersen_ptr;
- with hash_ptr {
- let (hash_state_ptr) = hash_init();
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, chain_id);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, contract_address);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, config_count);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, oracles_len);
- let (hash_state_ptr) = hash_update(
- hash_state_ptr, oracles, oracles_len * OracleConfig.SIZE
- );
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, f);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, onchain_config_len);
- let (hash_state_ptr) = hash_update(hash_state_ptr, onchain_config, onchain_config_len);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, offchain_config_version);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, offchain_config_len);
- let (hash_state_ptr) = hash_update(hash_state_ptr, offchain_config, offchain_config_len);
-
- let (hash) = hash_finalize(hash_state_ptr);
-
- // clamp the first two bytes with the config digest prefix
- let (masked) = bitwise_and(hash, DIGEST_MASK);
- let hash = masked + PREFIX;
-
- let pedersen_ptr = hash_ptr;
- return (hash=hash);
- }
-}
-
-@view
-func latest_config_details{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- config_count: felt, block_number: felt, config_digest: felt
-) {
- let (config_count) = Aggregator_config_count.read();
- let (block_number) = Aggregator_latest_config_block_number.read();
- let (config_digest) = Aggregator_latest_config_digest.read();
- return (config_count=config_count, block_number=block_number, config_digest=config_digest);
-}
-
-@view
-func transmitters{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- transmitters_len: felt, transmitters: felt*
-) {
- alloc_locals;
-
- let (result: felt*) = alloc();
- let (len) = Aggregator_oracles_len.read();
-
- transmitters_inner(len, 0, result);
-
- return (transmitters_len=len, transmitters=result);
-}
-
-// unroll transmitter list into a continuous array
-func transmitters_inner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- len: felt, index: felt, result: felt*
-) {
- if (len == 0) {
- return ();
- }
-
- let index = index + 1;
-
- let (transmitter) = Aggregator_transmitters_list.read(index);
- assert result[0] = transmitter;
-
- return transmitters_inner(len - 1, index, result + 1);
-}
-
-// --- Transmission ---
-
-struct Signature {
- r: felt,
- s: felt,
- public_key: felt,
-}
-
-struct ReportContext {
- config_digest: felt,
- epoch_and_round: felt,
- extra_hash: felt,
-}
-
-@external
-func transmit{
- syscall_ptr: felt*,
- pedersen_ptr: HashBuiltin*,
- ecdsa_ptr: SignatureBuiltin*,
- bitwise_ptr: BitwiseBuiltin*,
- range_check_ptr,
-}(
- report_context: ReportContext,
- observation_timestamp: felt,
- observers: felt,
- observations_len: felt,
- observations: felt*,
- juels_per_fee_coin: felt,
- gas_price: felt,
- signatures_len: felt,
- signatures: Signature*,
-) {
- alloc_locals;
-
- let (epoch_and_round) = Aggregator_latest_epoch_and_round.read();
- with_attr error_message("Aggregator: stale report") {
- assert_lt(epoch_and_round, report_context.epoch_and_round);
- }
-
- // validate transmitter
- let (caller) = get_caller_address();
- let (oracle: Oracle) = Aggregator_transmitters.read(caller);
- assert_not_zero(oracle.index); // 0 index = uninitialized
-
- // Validate config digest matches latest_config_digest
- let (config_digest) = Aggregator_latest_config_digest.read();
- with_attr error_message("Aggregator: config digest mismatch") {
- assert report_context.config_digest = config_digest;
- }
-
- let (f) = Aggregator_f.read();
- with_attr error_message("Aggregator: wrong number of signatures f={f}") {
- assert signatures_len = (f + 1);
- }
-
- let (msg) = hash_report(
- report_context,
- observation_timestamp,
- observers,
- observations_len,
- observations,
- juels_per_fee_coin,
- gas_price,
- );
- verify_signatures(msg, signatures, signatures_len, signed_count=0);
-
- // report():
-
- assert_nn_le(observations_len, MAX_ORACLES); // len <= MAX_ORACLES
- assert_lt(f, observations_len); // f < len
-
- Aggregator_latest_epoch_and_round.write(report_context.epoch_and_round);
-
- let (median_idx: felt, _) = unsigned_div_rem(observations_len, 2);
- let median = observations[median_idx];
-
- let is_neg = is_nn(median);
-
- // Check abs(median) is in i128 range.
- // NOTE: (assert_le_felt(-i128::MAX, median) doesn't work correctly so we have to use abs!)
- let value = abs_value(median);
- if (is_neg == 0) {
- with_attr error_message("Aggregator: value not in int128 range: {median}") {
- assert_le_felt(value, INT128_MAX + 1);
- }
- } else {
- with_attr error_message("Aggregator: value not in int128 range: {median}") {
- assert_le_felt(value, INT128_MAX);
- }
- }
-
- // Validate median in min-max range
- let (answer_range: Range) = Aggregator_answer_range.read();
- assert_in_range(median, answer_range.min, answer_range.max);
-
- let (local prev_round_id) = Aggregator_latest_aggregator_round_id.read();
- // let (prev_round_id) = Aggregator_latest_aggregator_round_id.read()
- let round_id = prev_round_id + 1;
- Aggregator_latest_aggregator_round_id.write(round_id);
-
- let (timestamp: felt) = get_block_timestamp();
- let (block_num: felt) = get_block_number();
-
- // write to storage
- Aggregator_transmissions.write(
- round_id,
- Transmission(
- answer=median,
- block_num=block_num,
- observation_timestamp=observation_timestamp,
- transmission_timestamp=timestamp,
- ),
- );
-
- // NOTE: Usually validating via validator would happen here, currently disabled
-
- let (billing: Billing) = Aggregator_billing.read();
-
- let (reimbursement_juels) = calculate_reimbursement(
- juels_per_fee_coin, signatures_len, gas_price, billing
- );
-
- // end report()
-
- NewTransmission.emit(
- round_id=round_id,
- answer=median,
- transmitter=caller,
- observation_timestamp=observation_timestamp,
- observers=observers,
- observations_len=observations_len,
- observations=observations,
- juels_per_fee_coin=juels_per_fee_coin,
- gas_price=gas_price,
- config_digest=report_context.config_digest,
- epoch_and_round=report_context.epoch_and_round,
- reimbursement=reimbursement_juels,
- );
-
- // pay transmitter
- let payment = reimbursement_juels + (billing.transmission_payment_gjuels * GIGA);
- // TODO: check overflow
-
- Aggregator_transmitters.write(
- caller, Oracle(index=oracle.index, payment_juels=oracle.payment_juels + payment)
- );
-
- return ();
-}
-
-func hash_report{pedersen_ptr: HashBuiltin*}(
- report_context: ReportContext,
- observation_timestamp: felt,
- observers: felt,
- observations_len: felt,
- observations: felt*,
- juels_per_fee_coin: felt,
- gas_price: felt,
-) -> (hash: felt) {
- let hash_ptr = pedersen_ptr;
- with hash_ptr {
- let (hash_state_ptr) = hash_init();
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, report_context.config_digest);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, report_context.epoch_and_round);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, report_context.extra_hash);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, observation_timestamp);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, observers);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, observations_len);
- let (hash_state_ptr) = hash_update(hash_state_ptr, observations, observations_len);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, juels_per_fee_coin);
- let (hash_state_ptr) = hash_update_single(hash_state_ptr, gas_price);
-
- let (hash) = hash_finalize(hash_state_ptr);
- let pedersen_ptr = hash_ptr;
- return (hash=hash);
- }
-}
-
-func verify_signatures{
- syscall_ptr: felt*,
- pedersen_ptr: HashBuiltin*,
- ecdsa_ptr: SignatureBuiltin*,
- bitwise_ptr: BitwiseBuiltin*,
- range_check_ptr,
-}(msg: felt, signatures: Signature*, signatures_len: felt, signed_count: felt) {
- alloc_locals;
-
- // 'signed_count' is used for tracking duplicate signatures
- if (signatures_len == 0) {
- // Check all signatures are unique (we only saw each pubkey once)
- // NOTE: This relies on protocol-level design constraints (MAX_ORACLES = 31, f = 10) which
- // ensures 31 bytes is enough to store a count for each oracle. Whenever the MAX_ORACLES
- // is updated the mask below should also be updated.
- assert MAX_ORACLES = 31;
- let (masked) = bitwise_and(
- signed_count, 0x01010101010101010101010101010101010101010101010101010101010101
- );
- with_attr error_message("Aggregator: duplicate signer") {
- assert signed_count = masked;
- }
- return ();
- }
-
- let signature = signatures[0];
-
- // Validate the signer key actually belongs to an oracle
- let (index) = Aggregator_signers.read(signature.public_key);
- with_attr error_message("Aggregator: invalid signer {signature.public_key}") {
- assert_not_zero(index); // 0 index = uninitialized
- }
-
- verify_ecdsa_signature(
- message=msg,
- public_key=signature.public_key,
- signature_r=signature.r,
- signature_s=signature.s,
- );
-
- // TODO: Using shifts here might be expensive due to pow()?
- // evaluate using alloc() to allocate a signed_count[oracles_len] instead
-
- // signed_count + 1 << (8 * index)
- let (shift) = pow(2, 8 * index);
- let signed_count = signed_count + shift;
-
- return verify_signatures(msg, signatures + Signature.SIZE, signatures_len - 1, signed_count);
-}
-
-@view
-func latest_transmission_details{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- ) -> (config_digest: felt, epoch_and_round: felt, latest_answer: felt, latest_timestamp: felt) {
- let (config_digest) = Aggregator_latest_config_digest.read();
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
- let (epoch_and_round) = Aggregator_latest_epoch_and_round.read();
- let (transmission: Transmission) = Aggregator_transmissions.read(latest_round_id);
-
- return (
- config_digest=config_digest,
- epoch_and_round=epoch_and_round,
- latest_answer=transmission.answer,
- latest_timestamp=transmission.transmission_timestamp,
- );
-}
-
-// --- RequestNewRound
-
-// --- Queries
-
-// Read access helper
-func require_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (address) = get_caller_address();
- SimpleReadAccessController.check_access(address);
-
- return ();
-}
-
-@view
-func description{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- description: felt
-) {
- require_access();
- let (description) = Aggregator_description.read();
- return (description,);
-}
-
-@view
-func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- require_access();
- let (decimals) = Aggregator_decimals.read();
- return (decimals,);
-}
-
-@view
-func round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) -> (round: Round) {
- require_access();
- // TODO: assert round_id fits in u32
-
- let (transmission: Transmission) = Aggregator_transmissions.read(round_id);
-
- let round = Round(
- round_id=round_id,
- answer=transmission.answer,
- block_num=transmission.block_num,
- started_at=transmission.observation_timestamp,
- updated_at=transmission.transmission_timestamp,
- );
- return (round,);
-}
-
-@view
-func latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- require_access();
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
- let (transmission: Transmission) = Aggregator_transmissions.read(latest_round_id);
-
- let round = Round(
- round_id=latest_round_id,
- answer=transmission.answer,
- block_num=transmission.block_num,
- started_at=transmission.observation_timestamp,
- updated_at=transmission.transmission_timestamp,
- );
- return (round,);
-}
-
-// --- Set PLI Token
-
-@storage_var
-func Aggregator_link_token() -> (token: felt) {
-}
-
-@event
-func LinkTokenSet(old_link_token: felt, new_link_token: felt) {
-}
-
-@external
-func set_link_token{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- link_token: felt, recipient: felt
-) {
- alloc_locals;
- Ownable.assert_only_owner();
-
- let (old_token) = Aggregator_link_token.read();
- if (link_token == old_token) {
- return ();
- }
-
- let (contract_address) = get_contract_address();
-
- // call balanceOf as a sanity check to confirm we're talking to a token
- IERC20.balanceOf(contract_address=link_token, account=contract_address);
-
- pay_oracles();
-
- // transfer remaining balance to recipient
- let (amount: Uint256) = IERC20.balanceOf(contract_address=link_token, account=contract_address);
- IERC20.transfer(contract_address=old_token, recipient=recipient, amount=amount);
-
- Aggregator_link_token.write(link_token);
-
- LinkTokenSet.emit(old_link_token=old_token, new_link_token=link_token);
-
- return ();
-}
-
-@view
-func link_token{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- link_token: felt
-) {
- let (link_token) = Aggregator_link_token.read();
- return (link_token,);
-}
-
-// --- Billing Access Controller
-
-@storage_var
-func Aggregator_billing_access_controller() -> (access_controller: felt) {
-}
-
-@event
-func BillingAccessControllerSet(old_controller: felt, new_controller: felt) {
-}
-
-@external
-func set_billing_access_controller{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- access_controller: felt
-) {
- Ownable.assert_only_owner();
-
- let (old_controller) = Aggregator_billing_access_controller.read();
- if (access_controller != old_controller) {
- Aggregator_billing_access_controller.write(access_controller);
-
- BillingAccessControllerSet.emit(
- old_controller=old_controller, new_controller=access_controller
- );
-
- return ();
- }
-
- return ();
-}
-
-@view
-func billing_access_controller{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- ) -> (access_controller: felt) {
- let (access_controller) = Aggregator_billing_access_controller.read();
- return (access_controller,);
-}
-
-// --- Billing Config
-
-struct Billing {
- // TODO: use a single felt via (observation_payment, transmission_payment) = split_felt()?
- observation_payment_gjuels: felt,
- transmission_payment_gjuels: felt,
- gas_base: felt,
- gas_per_signature: felt,
-}
-
-@storage_var
-func Aggregator_billing() -> (config: Billing) {
-}
-
-@view
-func billing{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- config: Billing
-) {
- let (config: Billing) = Aggregator_billing.read();
- return (config,);
-}
-
-@event
-func BillingSet(config: Billing) {
-}
-
-@external
-func set_billing{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(config: Billing) {
- has_billing_access();
-
- // Pay out oracles using existing settings for rounds up to now
- pay_oracles();
-
- // check payment value ranges within u32 bounds
- assert_nn_le(config.observation_payment_gjuels, UINT32_MAX);
- assert_nn_le(config.transmission_payment_gjuels, UINT32_MAX);
- assert_nn_le(config.gas_base, UINT32_MAX);
- assert_nn_le(config.gas_per_signature, UINT32_MAX);
-
- Aggregator_billing.write(config);
-
- BillingSet.emit(config=config);
-
- return ();
-}
-
-func has_billing_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (caller) = get_caller_address();
- let (owner) = Ownable.get_owner();
-
- // owner always has access
- if (caller == owner) {
- return ();
- }
-
- let (access_controller) = Aggregator_billing_access_controller.read();
-
- IAccessController.check_access(contract_address=access_controller, user=caller);
- return ();
-}
-
-// --- Payments and Withdrawals
-
-@event
-func OraclePaid(transmitter: felt, payee: felt, amount: Uint256, link_token: felt) {
-}
-
-@external
-func withdraw_payment{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- transmitter: felt
-) {
- alloc_locals;
- let (caller) = get_caller_address();
- let (payee) = Aggregator_payees.read(transmitter);
- with_attr error_message("Aggregator: only payee can withdraw") {
- assert caller = payee;
- }
-
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
- let (link_token) = Aggregator_link_token.read();
- pay_oracle(transmitter, latest_round_id, link_token);
- return ();
-}
-
-func _owed_payment{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- oracle: Oracle
-) -> (amount: felt) {
- if (oracle.index == 0) {
- return (0,);
- }
-
- let (billing: Billing) = Aggregator_billing.read();
-
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
- let (from_round_id) = reward_from_aggregator_round_id_.read(oracle.index);
- let rounds = latest_round_id - from_round_id;
-
- let amount = (rounds * billing.observation_payment_gjuels * GIGA) + oracle.payment_juels;
- return (amount,);
-}
-
-@external
-func owed_payment{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- transmitter: felt
-) -> (amount: felt) {
- let (oracle: Oracle) = Aggregator_transmitters.read(transmitter);
- let (amount: felt) = _owed_payment(oracle);
- return (amount,);
-}
-
-func pay_oracle{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- transmitter: felt, latest_round_id: felt, link_token: felt
-) {
- alloc_locals;
-
- let (oracle: Oracle) = Aggregator_transmitters.read(transmitter);
-
- if (oracle.index == 0) {
- return ();
- }
-
- let (amount_: felt) = _owed_payment(oracle);
- assert_nn(amount_);
-
- // if zero, fastpath return to avoid empty transfers
- if (amount_ == 0) {
- return ();
- }
-
- let (amount: Uint256) = felt_to_uint256(amount_);
- let (payee) = Aggregator_payees.read(transmitter);
-
- IERC20.transfer(contract_address=link_token, recipient=payee, amount=amount);
-
- // Reset payment
- reward_from_aggregator_round_id_.write(oracle.index, latest_round_id);
- Aggregator_transmitters.write(transmitter, Oracle(index=oracle.index, payment_juels=0));
-
- OraclePaid.emit(transmitter=transmitter, payee=payee, amount=amount, link_token=link_token);
-
- return ();
-}
-
-func pay_oracles{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (len) = Aggregator_oracles_len.read();
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
- let (link_token) = Aggregator_link_token.read();
- pay_oracles_(len, latest_round_id, link_token);
- return ();
-}
-
-func pay_oracles_{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- index: felt, latest_round_id: felt, link_token: felt
-) {
- if (index == 0) {
- return ();
- }
-
- let (transmitter) = Aggregator_transmitters_list.read(index);
- pay_oracle(transmitter, latest_round_id, link_token);
-
- return pay_oracles_(index - 1, latest_round_id, link_token);
-}
-
-@external
-func withdraw_funds{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- recipient: felt, amount: Uint256
-) {
- alloc_locals;
- has_billing_access();
- uint256_check(amount);
- let (link_token) = Aggregator_link_token.read();
- let (contract_address) = get_contract_address();
-
- let (link_due) = total_link_due();
- let (balance: Uint256) = IERC20.balanceOf(
- contract_address=link_token, account=contract_address
- );
-
- let (link_due_uint256: Uint256) = felt_to_uint256(link_due);
- let (res) = uint256_le(link_due_uint256, balance);
- with_attr error_message("Aggregator: total amount due exceeds the balance") {
- assert res = 1;
- }
-
- let (available: Uint256) = uint256_sub(balance, link_due_uint256);
-
- let (less_available: felt) = uint256_lt(available, amount);
- if (less_available == TRUE) {
- // Transfer as much as there is available
- IERC20.transfer(contract_address=link_token, recipient=recipient, amount=available);
- } else {
- IERC20.transfer(contract_address=link_token, recipient=recipient, amount=amount);
- }
-
- return ();
-}
-
-func total_link_due{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- due: felt
-) {
- let (len) = Aggregator_oracles_len.read();
- let (latest_round_id) = Aggregator_latest_aggregator_round_id.read();
-
- let (amount) = total_link_due_(len, latest_round_id, 0, 0);
- return (amount,);
-}
-
-func total_link_due_{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- index: felt, latest_round_id: felt, total_rounds: felt, payments_juels: felt
-) -> (due: felt) {
- if (index == 0) {
- let (billing: Billing) = Aggregator_billing.read();
- let amount = (total_rounds * billing.observation_payment_gjuels * GIGA) + payments_juels;
- return (amount,);
- }
-
- let (transmitter) = Aggregator_transmitters_list.read(index);
- let (oracle: Oracle) = Aggregator_transmitters.read(transmitter);
- assert_not_zero(oracle.index); // 0 == undefined
-
- let (from_round_id) = reward_from_aggregator_round_id_.read(oracle.index);
- let rounds = latest_round_id - from_round_id;
-
- let total_rounds = total_rounds + rounds;
- let payments_juels = payments_juels + oracle.payment_juels;
-
- return total_link_due_(index - 1, latest_round_id, total_rounds, payments_juels);
-}
-
-// since the felt type in Cairo is not signed, whoever calls this function will have to interpret the result line 1070 as the correct negative value.
-@view
-func link_available_for_payment{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- ) -> (available: felt) {
- alloc_locals;
- let (link_token) = Aggregator_link_token.read();
- let (contract_address) = get_contract_address();
-
- let (balance_: Uint256) = IERC20.balanceOf(
- contract_address=link_token, account=contract_address
- );
- // entire link supply fits into u96 so this should not fail
- let (balance) = uint256_to_felt(balance_);
-
- let (due) = total_link_due();
- let amount = balance - due;
-
- return (available=amount);
-}
-
-// --- Transmitter Payment
-
-const MARGIN = 115;
-
-func calculate_reimbursement{range_check_ptr}(
- juels_per_fee_coin: felt, signature_count: felt, gas_price: felt, config: Billing
-) -> (amount_juels: felt) {
- // Based on estimateFee (f=1 14977, f=2 14989, f=3 15002 f=4 15014 f=5 15027, count = f+1)
- // NOTE: seems a bit odd since each ecdsa is supposed to be 25.6 gas: https://docs.starknet.io/docs/Fees/fee-mechanism/
- // gas_base = 14951, gas_per_signature = 13
- let exact_gas = config.gas_base + (signature_count * config.gas_per_signature);
- let (gas: felt, _) = unsigned_div_rem(exact_gas * MARGIN, 100); // scale to 115% for some margin
- let amount = gas * gas_price;
- let amount_juels = amount * juels_per_fee_coin;
- return (amount_juels,);
-}
-
-// --- Payee Management
-
-@storage_var
-func Aggregator_payees(transmitter: felt) -> (payment_address: felt) {
-}
-
-@storage_var
-func Aggregator_proposed_payees(transmitter: felt) -> (payment_address: felt) {
-}
-
-@event
-func PayeeshipTransferRequested(transmitter: felt, current: felt, proposed: felt) {
-}
-
-@event
-func PayeeshipTransferred(transmitter: felt, previous: felt, current: felt) {
-}
-
-struct PayeeConfig {
- transmitter: felt,
- payee: felt,
-}
-
-@external
-func set_payees{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- payees_len: felt, payees: PayeeConfig*
-) {
- Ownable.assert_only_owner();
-
- set_payee(payees, payees_len);
-
- return ();
-}
-
-// Returns 1 if value == 0. Returns 0 otherwise.
-func is_zero(value) -> (res: felt) {
- if (value == 0) {
- return (res=1);
- }
-
- return (res=0);
-}
-
-func set_payee{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- payees: PayeeConfig*, len: felt
-) {
- if (len == 0) {
- return ();
- }
-
- let (current_payee) = Aggregator_payees.read(payees.transmitter);
-
- // a more convoluted way of saying
- // require(current_payee == 0 || current_payee == payee, "payee already set")
- let (is_unset) = is_zero(current_payee);
- let (is_same) = is_zero(current_payee - payees.payee);
- with_attr error_message("Aggregator: payee already set") {
- assert (is_unset - 1) * (is_same - 1) = 0;
- }
-
- Aggregator_payees.write(payees.transmitter, payees.payee);
-
- PayeeshipTransferred.emit(
- transmitter=payees.transmitter, previous=current_payee, current=payees.payee
- );
-
- return set_payee(payees + PayeeConfig.SIZE, len - 1);
-}
-
-@external
-func transfer_payeeship{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- transmitter: felt, proposed: felt
-) {
- with_attr error_message("Aggregator: cannot transfer payeeship to zero address") {
- assert_not_zero(proposed);
- }
- let (caller) = get_caller_address();
- let (payee) = Aggregator_payees.read(transmitter);
- with_attr error_message("Aggregator: only current payee can update") {
- assert caller = payee;
- }
- with_attr error_message("Aggregator: cannot transfer to self") {
- assert_not_equal(caller, proposed);
- }
-
- Aggregator_proposed_payees.write(transmitter, proposed);
-
- PayeeshipTransferRequested.emit(transmitter=transmitter, current=payee, proposed=proposed);
-
- return ();
-}
-
-@external
-func accept_payeeship{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- transmitter: felt
-) {
- let (proposed) = Aggregator_proposed_payees.read(transmitter);
- let (caller) = get_caller_address();
- with_attr error_message("Aggregator: only proposed payee can accept") {
- assert caller = proposed;
- }
-
- let (previous) = Aggregator_payees.read(transmitter);
- Aggregator_payees.write(transmitter, caller);
- Aggregator_proposed_payees.write(transmitter, 0);
-
- PayeeshipTransferred.emit(transmitter=transmitter, previous=previous, current=caller);
-
- return ();
-}
-
-@view
-func type_and_version() -> (meta: felt) {
- return ('ocr2/aggregator.cairo 1.0.0',);
-}
diff --git a/contracts/src/plugin/cairo/ocr2/aggregator_proxy.cairo b/contracts/src/plugin/cairo/ocr2/aggregator_proxy.cairo
deleted file mode 100644
index 749539f..0000000
--- a/contracts/src/plugin/cairo/ocr2/aggregator_proxy.cairo
+++ /dev/null
@@ -1,225 +0,0 @@
-// amarna: disable=arithmetic-div,arithmetic-sub,arithmetic-mul,arithmetic-add
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.math import split_felt, assert_not_zero
-from starkware.starknet.common.syscalls import get_caller_address
-
-from plugin.cairo.ocr2.IAggregator import IAggregator, Round
-
-from plugin.cairo.access.SimpleReadAccessController.library import SimpleReadAccessController
-from plugin.cairo.access.SimpleWriteAccessController.library import (
- owner,
- proposed_owner,
- transfer_ownership,
- accept_ownership,
- add_access,
- remove_access,
- enable_access_check,
- disable_access_check,
-)
-from plugin.cairo.access.ownable import Ownable
-
-struct Phase {
- id: felt,
- aggregator: felt,
-}
-
-@storage_var
-func AggregatorProxy_current_phase() -> (phase: Phase) {
-}
-
-@storage_var
-func AggregatorProxy_proposed_aggregator() -> (address: felt) {
-}
-
-@storage_var
-func AggregatorProxy_phases(id: felt) -> (address: felt) {
-}
-
-const SHIFT = 2 ** 128;
-const MAX_ID = SHIFT - 1;
-
-@event
-func AggregatorProposed(current: felt, proposed: felt) {
-}
-
-@event
-func AggregatorConfirmed(previous: felt, latest: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner: felt, address: felt
-) {
- SimpleReadAccessController.initialize(owner); // This also calls Ownable.initializer
- set_aggregator(address);
- return ();
-}
-
-func set_aggregator{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- address: felt
-) {
- let (current_phase: Phase) = AggregatorProxy_current_phase.read();
- let id = current_phase.id + 1;
- AggregatorProxy_current_phase.write(Phase(id=id, aggregator=address));
- AggregatorProxy_phases.write(id, address);
- return ();
-}
-
-@external
-func propose_aggregator{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- address: felt
-) {
- Ownable.assert_only_owner();
- with_attr error_message("AggregatorProxy: aggregator is zero address") {
- assert_not_zero(address);
- }
- AggregatorProxy_proposed_aggregator.write(address);
-
- // emit event
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- AggregatorProposed.emit(current=phase.aggregator, proposed=address);
- return ();
-}
-
-@external
-func confirm_aggregator{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- address: felt
-) {
- Ownable.assert_only_owner();
- with_attr error_message("AggregatorProxy: aggregator is zero address") {
- assert_not_zero(address);
- }
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- let previous = phase.aggregator;
-
- let (proposed_aggregator) = AggregatorProxy_proposed_aggregator.read();
- assert proposed_aggregator = address;
- AggregatorProxy_proposed_aggregator.write(0);
- set_aggregator(proposed_aggregator);
-
- // emit event
- AggregatorConfirmed.emit(previous=previous, latest=address);
- return ();
-}
-
-// Read access helper
-func require_access{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- let (address) = get_caller_address();
- SimpleReadAccessController.check_access(address);
-
- return ();
-}
-
-@view
-func latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- require_access();
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=phase.aggregator);
-
- // Add phase_id to the high bits of round_id
- let round_id = round.round_id + (phase.id * SHIFT);
- return (
- Round(
- round_id=round_id,
- answer=round.answer,
- block_num=round.block_num,
- started_at=round.started_at,
- updated_at=round.updated_at,
- ),
- );
-}
-
-@view
-func round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) -> (round: Round) {
- require_access();
- let (phase_id, round_id) = split_felt(round_id);
- let (address) = AggregatorProxy_phases.read(phase_id);
- assert_not_zero(address);
-
- let (round: Round) = IAggregator.round_data(contract_address=address, round_id=round_id);
- // Add phase_id to the high bits of round_id
- let round_id = round.round_id + (phase_id * SHIFT);
- return (
- Round(
- round_id=round_id,
- answer=round.answer,
- block_num=round.block_num,
- started_at=round.started_at,
- updated_at=round.updated_at,
- ),
- );
-}
-
-// These read from the proposed aggregator as a way to test the aggregator before making setting it live.
-
-@view
-func proposed_latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- ) -> (round: Round) {
- require_access();
- let (aggregator) = AggregatorProxy_proposed_aggregator.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=aggregator);
- return (round,);
-}
-
-@view
-func proposed_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- round_id: felt
-) -> (round: Round) {
- require_access();
- let (aggregator) = AggregatorProxy_proposed_aggregator.read();
- let (round: Round) = IAggregator.round_data(contract_address=aggregator, round_id=round_id);
- return (round,);
-}
-
-@view
-func aggregator{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- aggregator: felt
-) {
- require_access();
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- return (phase.aggregator,);
-}
-
-@view
-func phase_id{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- phase_id: felt
-) {
- require_access();
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- return (phase.id,);
-}
-
-@view
-func description{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- description: felt
-) {
- require_access();
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- let (description) = IAggregator.description(contract_address=phase.aggregator);
- return (description,);
-}
-
-@view
-func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- require_access();
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- let (decimals) = IAggregator.decimals(contract_address=phase.aggregator);
- return (decimals,);
-}
-
-@view
-func type_and_version{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- meta: felt
-) {
- let (phase: Phase) = AggregatorProxy_current_phase.read();
- let (meta) = IAggregator.type_and_version(contract_address=phase.aggregator);
- return (meta,);
-}
diff --git a/contracts/src/plugin/cairo/ocr2/mocks/MockAggregator.cairo b/contracts/src/plugin/cairo/ocr2/mocks/MockAggregator.cairo
deleted file mode 100644
index adc4941..0000000
--- a/contracts/src/plugin/cairo/ocr2/mocks/MockAggregator.cairo
+++ /dev/null
@@ -1,94 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.alloc import alloc
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from plugin.cairo.ocr2.IAggregator import NewTransmission, Round
-
-struct Transmission {
- answer: felt,
- block_num: felt,
- observation_timestamp: felt,
- transmission_timestamp: felt,
-}
-
-@storage_var
-func MockAggregator_transmissions(round_id: felt) -> (transmission: Transmission) {
-}
-
-@storage_var
-func MockAggregator_latest_aggregator_round_id() -> (round_id: felt) {
-}
-
-@storage_var
-func MockAggregator_decimals() -> (decimals: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(decimals: felt) {
- MockAggregator_decimals.write(decimals);
- return ();
-}
-
-@external
-func set_latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- answer: felt, block_num: felt, observation_timestamp: felt, transmission_timestamp: felt
-) {
- alloc_locals;
- let (prev_round_id) = MockAggregator_latest_aggregator_round_id.read();
- let round_id = prev_round_id + 1;
- MockAggregator_latest_aggregator_round_id.write(round_id);
- MockAggregator_transmissions.write(
- round_id,
- Transmission(
- answer=answer,
- block_num=block_num,
- observation_timestamp=observation_timestamp,
- transmission_timestamp=transmission_timestamp,
- ),
- );
-
- let (observations: felt*) = alloc();
- assert observations[0] = 2;
- assert observations[1] = 3;
- NewTransmission.emit(
- round_id=round_id,
- answer=answer,
- transmitter=12,
- observation_timestamp=observation_timestamp,
- observers=3,
- observations_len=2,
- observations=observations,
- juels_per_fee_coin=18,
- gas_price=1,
- config_digest=34,
- epoch_and_round=20,
- reimbursement=100,
- );
- return ();
-}
-
-@view
-func latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- alloc_locals;
- let (latest_round_id) = MockAggregator_latest_aggregator_round_id.read();
- let (transmission: Transmission) = MockAggregator_transmissions.read(latest_round_id);
-
- let round = Round(
- round_id=latest_round_id,
- answer=transmission.answer,
- block_num=transmission.block_num,
- started_at=transmission.observation_timestamp,
- updated_at=transmission.transmission_timestamp,
- );
- return (round,);
-}
-
-@view
-func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- let (decimals) = MockAggregator_decimals.read();
- return (decimals,);
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/IERC677.cairo b/contracts/src/plugin/cairo/token/ERC677/IERC677.cairo
deleted file mode 100644
index 7854c87..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/IERC677.cairo
+++ /dev/null
@@ -1,13 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.uint256 import Uint256
-
-@event
-func Transfer(from_: felt, to: felt, value: Uint256, data_len: felt, data: felt*) {
-}
-
-@contract_interface
-namespace IERC677 {
- func transferAndCall(to: felt, value: Uint256, data_len: felt, data: felt*) -> (success: felt) {
- }
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/IERC677Receiver.cairo b/contracts/src/plugin/cairo/token/ERC677/IERC677Receiver.cairo
deleted file mode 100644
index 6db1039..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/IERC677Receiver.cairo
+++ /dev/null
@@ -1,12 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.uint256 import Uint256
-
-@contract_interface
-namespace IERC677Receiver {
- func onTokenTransfer(sender: felt, value: Uint256, data_len: felt, data: felt*) {
- }
-
- func supportsInterface(interface_id: felt) -> (success: felt) {
- }
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/README.md b/contracts/src/plugin/cairo/token/ERC677/README.md
deleted file mode 100644
index 635f672..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Plugin ERC677
-
-## starkgate_token.cairo
-
-Similar to the starkgate ERC20 contract but with some added functionality from ERC677.
-
-### transferAndCall
-
-Transfers tokens to receiver, via ERC20's `transfer(address, address, uint256)` function. It then logs an event `Transfer(address,address,uint256,bytes)`.
-
-Once the transfer has succeeded and the event is logged, the token calls `onTokenTransfer(sender, value, data_len, data)` on the receiver with `data[0]` as the function's selector, and all the parameters required by the function that you want to call next.
-
-## Receiver contract
-
-### onTokenTransfer
-
-This function is added to contracts enabling them to react to receiving tokens within a single transaction. The `data[0]` parameter is the selector of the function that you want to call.
-The data paramater contains all the parameters required by the function that you want to call through the selector.
diff --git a/contracts/src/plugin/cairo/token/ERC677/library.cairo b/contracts/src/plugin/cairo/token/ERC677/library.cairo
deleted file mode 100644
index e1b865c..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/library.cairo
+++ /dev/null
@@ -1,38 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.uint256 import Uint256, uint256_check
-from starkware.starknet.common.syscalls import get_caller_address
-from starkware.cairo.common.bool import TRUE
-from openzeppelin.token.erc20.library import ERC20
-from plugin.cairo.token.ERC677.IERC677Receiver import IERC677Receiver
-from plugin.cairo.token.ERC677.IERC677 import Transfer
-
-const IERC677_RECEIVER_ID = 0x4f3dcd;
-
-// https://github.com/ethereum/EIPs/issues/677
-namespace ERC677 {
- // All non-account contracts that want to receive the `transferAndCall` need to implement ERC165 + ERC677, or revert.
- // All account contracts need to implement ERC165 (to be detected as an account, or revert), and optionally ERC677
- // if they want to be triggered, if not they'll still receive funds but not the trigger.
- func transfer_and_call{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- to: felt, value: Uint256, data_len: felt, data: felt*
- ) -> (success: felt) {
- alloc_locals;
-
- uint256_check(value);
- let (sender) = get_caller_address();
-
- // ERC20.transfer will check that both addresses are not zero
- ERC20.transfer(to, value);
- Transfer.emit(sender, to, value, data_len, data);
-
- // TODO: should we always just return TRUE, for all cases?
- let (bool) = IERC677Receiver.supportsInterface(to, IERC677_RECEIVER_ID);
- if (bool == TRUE) {
- IERC677Receiver.onTokenTransfer(to, sender, value, data_len, data);
- return (TRUE,);
- }
- return (TRUE,);
- }
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/mock/link_receiver.cairo b/contracts/src/plugin/cairo/token/ERC677/mock/link_receiver.cairo
deleted file mode 100644
index f724f70..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/mock/link_receiver.cairo
+++ /dev/null
@@ -1,105 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.bool import TRUE
-from starkware.cairo.common.uint256 import Uint256, uint256_check
-from starkware.starknet.common.syscalls import get_contract_address, library_call
-from starkware.cairo.common.math import assert_not_zero
-
-from openzeppelin.introspection.erc165.library import ERC165
-from openzeppelin.token.erc20.IERC20 import IERC20
-
-const IERC677_RECEIVER_ID = 0x4f3dcd;
-
-@storage_var
-func linkReceiver_fallback_called_() -> (bool: felt) {
-}
-
-@storage_var
-func linkReceiver_call_data_called_() -> (bool: felt) {
-}
-
-@storage_var
-func linkReceiver_tokens_received_() -> (value: Uint256) {
-}
-
-@storage_var
-func linkReceiver_implementation_hash_() -> (class_hash: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- class_hash: felt
-) {
- ERC165.register_interface(IERC677_RECEIVER_ID);
- linkReceiver_implementation_hash_.write(class_hash);
- return ();
-}
-
-@external
-func onTokenTransfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- sender: felt, value: Uint256, data_len: felt, data: felt*
-) {
- uint256_check(value);
- with_attr error_message(
- "LinkReceiver: data_len must not be null. It needs at least one selector") {
- assert_not_zero(data_len);
- }
- linkReceiver_fallback_called_.write(TRUE);
- let (class_hash) = linkReceiver_implementation_hash_.read();
- let selector = data[0];
- let data = data + 1;
- library_call(class_hash, selector, data_len - 1, data);
- return ();
-}
-
-@external
-func callbackWithoutWithdrawl{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- linkReceiver_call_data_called_.write(TRUE);
- return ();
-}
-
-@external
-func callbackWithWithdrawl{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- value_high: felt, value_low: felt, sender: felt, token_addr: felt
-) {
- let value: Uint256 = Uint256(low=value_low, high=value_high);
- linkReceiver_call_data_called_.write(TRUE);
- let (contract_address) = get_contract_address();
- IERC20.transferFrom(token_addr, sender, contract_address, value);
-
- linkReceiver_tokens_received_.write(value);
- return ();
-}
-
-@view
-func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- interface_id: felt
-) -> (success: felt) {
- let (success) = ERC165.supports_interface(interface_id);
- return (success,);
-}
-
-@view
-func getFallback{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- bool: felt
-) {
- let (bool) = linkReceiver_fallback_called_.read();
- return (bool,);
-}
-
-@view
-func getCallData{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- bool: felt
-) {
- let (bool) = linkReceiver_call_data_called_.read();
- return (bool,);
-}
-
-@view
-func getTokens{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- value: Uint256
-) {
- let (value) = linkReceiver_tokens_received_.read();
- return (value,);
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/mock/not_erc677_compatible.cairo b/contracts/src/plugin/cairo/token/ERC677/mock/not_erc677_compatible.cairo
deleted file mode 100644
index 88c3528..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/mock/not_erc677_compatible.cairo
+++ /dev/null
@@ -1,8 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- return ();
-}
diff --git a/contracts/src/plugin/cairo/token/ERC677/mock/token677_receiver_mock.cairo b/contracts/src/plugin/cairo/token/ERC677/mock/token677_receiver_mock.cairo
deleted file mode 100644
index 74c304a..0000000
--- a/contracts/src/plugin/cairo/token/ERC677/mock/token677_receiver_mock.cairo
+++ /dev/null
@@ -1,92 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.bool import TRUE, FALSE
-from starkware.cairo.common.uint256 import Uint256, uint256_check
-from openzeppelin.introspection.erc165.library import ERC165
-
-const IERC677_RECEIVER_ID = 0x4f3dcd;
-
-@storage_var
-func token677ReceiverMock_token_sender_() -> (address: felt) {
-}
-
-@storage_var
-func token677ReceiverMock_sent_value_() -> (value: Uint256) {
-}
-
-@storage_var
-func token677ReceiverMock_token_data_(index: felt) -> (data: felt) {
-}
-
-@storage_var
-func token677ReceiverMock_token_data_len_() -> (data_len: felt) {
-}
-
-@storage_var
-func token677ReceiverMock_called_fallback_() -> (bool: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- ERC165.register_interface(IERC677_RECEIVER_ID);
- token677ReceiverMock_called_fallback_.write(FALSE);
- return ();
-}
-
-@external
-func onTokenTransfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- sender: felt, value: Uint256, data_len: felt, data: felt*
-) {
- uint256_check(value);
- token677ReceiverMock_called_fallback_.write(TRUE);
- token677ReceiverMock_token_sender_.write(sender);
- token677ReceiverMock_sent_value_.write(value);
- token677ReceiverMock_token_data_len_.write(data_len);
- fillDataStorage(0, data_len, data);
- return ();
-}
-
-func fillDataStorage{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- index: felt, data_len: felt, data: felt*
-) {
- if (data_len == 0) {
- return ();
- }
-
- let index = index + 1;
- token677ReceiverMock_token_data_.write(index, [data]);
- return fillDataStorage(index=index, data_len=data_len - 1, data=data + 1);
-}
-
-@view
-func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- interface_id: felt
-) -> (success: felt) {
- let (success) = ERC165.supports_interface(interface_id);
- return (success,);
-}
-
-@view
-func getCalledFallback{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- bool: felt
-) {
- let (bool) = token677ReceiverMock_called_fallback_.read();
- return (bool,);
-}
-
-@view
-func getSentValue{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- value: Uint256
-) {
- let (value) = token677ReceiverMock_sent_value_.read();
- return (value,);
-}
-
-@view
-func getTokenSender{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- address: felt
-) {
- let (address) = token677ReceiverMock_token_sender_.read();
- return (address,);
-}
diff --git a/contracts/src/plugin/cairo/token/IMintableToken.cairo b/contracts/src/plugin/cairo/token/IMintableToken.cairo
deleted file mode 100644
index a8bad6b..0000000
--- a/contracts/src/plugin/cairo/token/IMintableToken.cairo
+++ /dev/null
@@ -1,12 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.uint256 import Uint256
-
-@contract_interface
-namespace IMintableToken {
- func permissionedMint(account: felt, amount: Uint256) {
- }
-
- func permissionedBurn(account: felt, amount: Uint256) {
- }
-}
diff --git a/contracts/src/plugin/cairo/token/starkgate/presets/link_token.cairo b/contracts/src/plugin/cairo/token/starkgate/presets/link_token.cairo
deleted file mode 100644
index 3d9f449..0000000
--- a/contracts/src/plugin/cairo/token/starkgate/presets/link_token.cairo
+++ /dev/null
@@ -1,168 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.uint256 import Uint256
-from starkware.cairo.common.bool import TRUE
-
-from openzeppelin.token.erc20.library import ERC20
-
-from starkware.starknet.std_contracts.ERC20.permitted import (
- permitted_initializer,
- permitted_minter_only,
-)
-
-from plugin.cairo.token.ERC677.library import ERC677
-
-const NAME = 'Plugin Token';
-const SYMBOL = 'PLI';
-const DECIMALS = 18;
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) {
- ERC20.initializer(NAME, SYMBOL, DECIMALS);
- permitted_initializer(owner);
- return ();
-}
-
-//
-// Getters
-//
-
-@view
-func type_and_version() -> (meta: felt) {
- return ('LinkToken 0.0.1',);
-}
-
-@view
-func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {
- let (name) = ERC20.name();
- return (name,);
-}
-
-@view
-func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {
- let (symbol) = ERC20.symbol();
- return (symbol,);
-}
-
-@view
-func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- totalSupply: Uint256
-) {
- let (totalSupply: Uint256) = ERC20.total_supply();
- return (totalSupply,);
-}
-
-@view
-func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- let (decimals) = ERC20.decimals();
- return (decimals,);
-}
-
-@view
-func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(account: felt) -> (
- balance: Uint256
-) {
- let (balance: Uint256) = ERC20.balance_of(account);
- return (balance,);
-}
-
-@view
-func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- owner: felt, spender: felt
-) -> (remaining: Uint256) {
- let (remaining: Uint256) = ERC20.allowance(owner, spender);
- return (remaining,);
-}
-
-//
-// Externals
-//
-
-@external
-func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- recipient: felt, amount: Uint256
-) -> (success: felt) {
- ERC20.transfer(recipient, amount);
- return (TRUE,);
-}
-
-@external
-func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- sender: felt, recipient: felt, amount: Uint256
-) -> (success: felt) {
- ERC20.transfer_from(sender, recipient, amount);
- return (TRUE,);
-}
-
-@external
-func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- spender: felt, amount: Uint256
-) -> (success: felt) {
- ERC20.approve(spender, amount);
- return (TRUE,);
-}
-
-@external
-func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- spender: felt, added_value: Uint256
-) -> (success: felt) {
- ERC20.increase_allowance(spender, added_value);
- return (TRUE,);
-}
-
-@external
-func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- spender: felt, subtracted_value: Uint256
-) -> (success: felt) {
- ERC20.decrease_allowance(spender, subtracted_value);
- return (TRUE,);
-}
-
-//
-// Externals - ERC677
-//
-
-@external
-func transferAndCall{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- to: felt, value: Uint256, data_len: felt, data: felt*
-) -> (success: felt) {
- ERC677.transfer_and_call(to, value, data_len, data);
- return (TRUE,);
-}
-
-//
-// Externals - StarkGate IMintableToken interface
-//
-
-@external
-func permissionedMint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- account: felt, amount: Uint256
-) {
- alloc_locals;
- with_attr error_message("LinkToken: no permission") {
- permitted_minter_only();
- }
- local syscall_ptr: felt* = syscall_ptr;
-
- ERC20._mint(recipient=account, amount=amount);
-
- return ();
-}
-
-@external
-func permissionedBurn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- account: felt, amount: Uint256
-) {
- alloc_locals;
- with_attr error_message("LinkToken: no permission") {
- permitted_minter_only();
- }
- local syscall_ptr: felt* = syscall_ptr;
-
- ERC20._burn(account=account, amount=amount);
-
- return ();
-}
diff --git a/contracts/src/plugin/cairo/utils.cairo b/contracts/src/plugin/cairo/utils.cairo
deleted file mode 100644
index cacd3d2..0000000
--- a/contracts/src/plugin/cairo/utils.cairo
+++ /dev/null
@@ -1,18 +0,0 @@
-from starkware.cairo.common.math import assert_in_range, assert_lt_felt
-from starkware.cairo.common.uint256 import Uint256
-from starkware.cairo.common.math import split_felt
-
-func assert_boolean{range_check_ptr}(value: felt) {
- // Asserts that value is in the range [0, 2).
- return assert_in_range(value, 0, 2);
-}
-
-func felt_to_uint256{range_check_ptr}(x) -> (uint_x: Uint256) {
- let (high, low) = split_felt(x);
- return (Uint256(low=low, high=high),);
-}
-
-func uint256_to_felt{range_check_ptr}(value: Uint256) -> (value: felt) {
- assert_lt_felt(value.high, 2 ** 123);
- return (value.high * (2 ** 128) + value.low,);
-}
diff --git a/contracts/src/tests.cairo b/contracts/src/tests.cairo
new file mode 100644
index 0000000..4d81044
--- /dev/null
+++ b/contracts/src/tests.cairo
@@ -0,0 +1,12 @@
+// Cairo files in folders can only be imported from a file of the same name as the folder
+
+mod test_aggregator;
+mod test_aggregator_proxy;
+mod test_multisig;
+mod test_ownable;
+mod test_erc677;
+mod test_link_token;
+mod test_upgradeable;
+mod test_access_controller;
+mod test_mock_aggregator;
+mod test_sequencer_uptime_feed;
diff --git a/contracts/src/tests/test_access_controller.cairo b/contracts/src/tests/test_access_controller.cairo
new file mode 100644
index 0000000..c48a43b
--- /dev/null
+++ b/contracts/src/tests/test_access_controller.cairo
@@ -0,0 +1,88 @@
+use starknet::ContractAddress;
+use starknet::testing::set_caller_address;
+use starknet::testing::set_contract_address;
+use starknet::contract_address_const;
+use starknet::class_hash::class_hash_const;
+use starknet::class_hash::Felt252TryIntoClassHash;
+use starknet::syscalls::deploy_syscall;
+
+use array::ArrayTrait;
+use traits::Into;
+use traits::TryInto;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::access_control::access_controller::AccessController;
+use plugin::access_control::access_controller::AccessController::UpgradeableImpl;
+
+use plugin::libraries::access_control::{
+ IAccessController, IAccessControllerDispatcher, IAccessControllerDispatcherTrait
+};
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+
+fn STATE() -> AccessController::ContractState {
+ AccessController::contract_state_for_testing()
+}
+
+fn setup() -> ContractAddress {
+ let account: ContractAddress = contract_address_const::<777>();
+ start_cheat_caller_address_global(account);
+ account
+}
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_upgrade_not_owner() {
+ let _ = setup();
+ let mut state = STATE();
+
+ UpgradeableImpl::upgrade(ref state, class_hash_const::<2>());
+}
+
+#[test]
+fn test_access_control() {
+ let owner = setup();
+ // Deploy access controller
+ let calldata = array![owner.into(), // owner
+ ];
+
+ let (accessControllerAddr, _) = declare("AccessController").unwrap().deploy(@calldata).unwrap();
+
+ should_implement_access_control(accessControllerAddr, owner);
+}
+
+//
+// Tests for contracts that inherit AccessControl.
+// Write functions are assumed to be protected by Ownable::only_owner,
+// but this test does not check for that.
+//
+
+fn should_implement_access_control(contract_addr: ContractAddress, owner: ContractAddress) {
+ let contract = IAccessControllerDispatcher { contract_address: contract_addr };
+ let acc2: ContractAddress = contract_address_const::<2222987765>();
+
+ start_cheat_caller_address_global(owner);
+
+ // access check is enabled by default
+ assert(!contract.has_access(acc2, array![]), 'should not have access');
+
+ // disable access check
+ contract.disable_access_check();
+ assert(contract.has_access(acc2, array![]), 'should have access');
+
+ // enable access check
+ contract.enable_access_check();
+ assert(!contract.has_access(acc2, array![]), 'should not have access');
+
+ // add_access for acc2
+ contract.add_access(acc2);
+ assert(contract.has_access(acc2, array![]), 'should have access');
+
+ // remove_access for acc2
+ contract.remove_access(acc2);
+ assert(!contract.has_access(acc2, array![]), 'should not have access');
+}
diff --git a/contracts/src/tests/test_aggregator.cairo b/contracts/src/tests/test_aggregator.cairo
new file mode 100644
index 0000000..26df5ca
--- /dev/null
+++ b/contracts/src/tests/test_aggregator.cairo
@@ -0,0 +1,430 @@
+use starknet::testing::set_caller_address;
+use starknet::testing::set_contract_address;
+use starknet::ContractAddress;
+use starknet::contract_address_const;
+use starknet::class_hash::class_hash_const;
+use starknet::class_hash::Felt252TryIntoClassHash;
+use starknet::syscalls::deploy_syscall;
+
+use array::ArrayTrait;
+use clone::Clone;
+use traits::Into;
+use traits::TryInto;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::ocr2::aggregator::pow;
+use plugin::ocr2::aggregator::Aggregator;
+use plugin::ocr2::aggregator::Aggregator::{
+ AggregatorImpl, BillingImpl, PayeeManagementImpl, UpgradeableImpl
+};
+use plugin::ocr2::aggregator::Aggregator::BillingConfig;
+use plugin::ocr2::aggregator::Aggregator::PayeeConfig;
+use plugin::access_control::access_controller::AccessController;
+use plugin::token::link_token::LinkToken;
+use plugin::tests::test_ownable::should_implement_ownable;
+use plugin::tests::test_access_controller::should_implement_access_control;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+#[test]
+fn test_pow_2_0() {
+ assert(pow(2, 0) == 0x1, 'expected 0x1');
+ assert(pow(2, 1) == 0x2, 'expected 0x2');
+ assert(pow(2, 2) == 0x4, 'expected 0x4');
+ assert(pow(2, 3) == 0x8, 'expected 0x8');
+ assert(pow(2, 4) == 0x10, 'expected 0x10');
+ assert(pow(2, 5) == 0x20, 'expected 0x20');
+ assert(pow(2, 6) == 0x40, 'expected 0x40');
+ assert(pow(2, 7) == 0x80, 'expected 0x80');
+ assert(pow(2, 8) == 0x100, 'expected 0x100');
+ assert(pow(2, 9) == 0x200, 'expected 0x200');
+ assert(pow(2, 10) == 0x400, 'expected 0x400');
+ assert(pow(2, 11) == 0x800, 'expected 0x800');
+ assert(pow(2, 12) == 0x1000, 'expected 0x1000');
+ assert(pow(2, 13) == 0x2000, 'expected 0x2000');
+ assert(pow(2, 14) == 0x4000, 'expected 0x4000');
+ assert(pow(2, 15) == 0x8000, 'expected 0x8000');
+ assert(pow(2, 16) == 0x10000, 'expected 0x10000');
+ assert(pow(2, 17) == 0x20000, 'expected 0x20000');
+ assert(pow(2, 18) == 0x40000, 'expected 0x40000');
+ assert(pow(2, 19) == 0x80000, 'expected 0x80000');
+ assert(pow(2, 20) == 0x100000, 'expected 0x100000');
+ assert(pow(2, 21) == 0x200000, 'expected 0x200000');
+ assert(pow(2, 22) == 0x400000, 'expected 0x400000');
+ assert(pow(2, 23) == 0x800000, 'expected 0x800000');
+ assert(pow(2, 24) == 0x1000000, 'expected 0x1000000');
+ assert(pow(2, 25) == 0x2000000, 'expected 0x2000000');
+ assert(pow(2, 26) == 0x4000000, 'expected 0x4000000');
+ assert(pow(2, 27) == 0x8000000, 'expected 0x8000000');
+ assert(pow(2, 28) == 0x10000000, 'expected 0x10000000');
+ assert(pow(2, 29) == 0x20000000, 'expected 0x20000000');
+ assert(pow(2, 30) == 0x40000000, 'expected 0x40000000');
+ assert(pow(2, 31) == 0x80000000, 'expected 0x80000000');
+}
+
+use plugin::libraries::access_control::{
+ IAccessController, IAccessControllerDispatcher, IAccessControllerDispatcherTrait
+};
+
+#[starknet::interface]
+trait ILinkToken {}
+
+fn STATE() -> Aggregator::ContractState {
+ Aggregator::contract_state_for_testing()
+}
+
+fn setup() -> (
+ ContractAddress, ContractAddress, IAccessControllerDispatcher, ILinkTokenDispatcher
+) {
+ let acc1: ContractAddress = contract_address_const::<777>();
+ let acc2: ContractAddress = contract_address_const::<888>();
+ // set acc1 as default caller
+ start_cheat_caller_address_global(acc1);
+
+ // deploy billing access controller
+ let calldata = array![acc1.into(), // owner = acc1;
+ ];
+
+ let (billingAccessControllerAddr, _) = declare("AccessController")
+ .unwrap()
+ .deploy(@calldata)
+ .unwrap();
+
+ let billingAccessController = IAccessControllerDispatcher {
+ contract_address: billingAccessControllerAddr
+ };
+
+ // deploy link token contract
+ let calldata = array![acc1.into(), // minter = acc1;
+ acc1.into(), // owner = acc1;
+ ];
+
+ let (linkTokenAddr, _) = declare("LinkToken").unwrap().deploy(@calldata).unwrap();
+
+ let linkToken = ILinkTokenDispatcher { contract_address: linkTokenAddr };
+
+ // return accounts, billing access controller, link token
+ (acc1, acc2, billingAccessController, linkToken)
+}
+
+#[test]
+fn test_ownable() {
+ let (account, _, _, _) = setup();
+ // Deploy aggregator
+ let calldata = array![
+ account.into(), // owner
+ contract_address_const::<777>().into(), // link token
+ 0, // min_answer
+ 100, // max_answer
+ contract_address_const::<999>().into(), // billing access controller
+ 8, // decimals
+ 123, // description
+ ];
+
+ let (aggregatorAddr, _) = declare("Aggregator").unwrap().deploy(@calldata).unwrap();
+
+ should_implement_ownable(aggregatorAddr, account);
+}
+
+#[test]
+fn test_access_control() {
+ let (account, _, _, _) = setup();
+ // Deploy aggregator
+ let mut calldata = array![
+ account.into(), // owner
+ contract_address_const::<777>().into(), // link token
+ 0, // min_answer
+ 100, // max_answer
+ contract_address_const::<999>().into(), // billing access controller
+ 8, // decimals
+ 123, // description
+ ];
+
+ let (aggregatorAddr, _) = declare("Aggregator").unwrap().deploy(@calldata).unwrap();
+
+ // let (aggregatorAddr, _) = deploy_syscall(
+ // Aggregator::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false
+ // )
+ // .unwrap();
+
+ should_implement_access_control(aggregatorAddr, account);
+}
+
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_upgrade_non_owner() {
+ let _ = setup();
+ let mut state = STATE();
+
+ UpgradeableImpl::upgrade(ref state, class_hash_const::<123>());
+}
+
+// --- Billing tests ---
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_set_billing_access_controller_not_owner() {
+ let (owner, acc2, billingAccessController, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ // set billing access controller should revert if caller is not owner
+ start_cheat_caller_address_global(acc2);
+ BillingImpl::set_billing_access_controller(ref state, billingAccessController.contract_address);
+}
+
+#[test]
+#[should_panic(expected: ('caller does not have access',))]
+fn test_set_billing_config_no_access() {
+ let (owner, acc2, billingAccessController, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state,
+ owner,
+ contract_address_const::<777>(),
+ 0,
+ 100,
+ billingAccessController.contract_address,
+ 8,
+ 123
+ );
+
+ // set billing config as acc2 with no access
+ let config = BillingConfig {
+ observation_payment_gjuels: 1,
+ transmission_payment_gjuels: 5,
+ gas_base: 1,
+ gas_per_signature: 1,
+ };
+ start_cheat_caller_address_global(acc2);
+ BillingImpl::set_billing(ref state, config);
+}
+
+#[test]
+fn test_set_billing_config_as_owner() {
+ let (owner, _, billingAccessController, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state,
+ owner,
+ contract_address_const::<777>(),
+ 0,
+ 100,
+ billingAccessController.contract_address,
+ 8,
+ 123
+ );
+
+ // set billing config as owner
+ let config = BillingConfig {
+ observation_payment_gjuels: 1,
+ transmission_payment_gjuels: 5,
+ gas_base: 1,
+ gas_per_signature: 1,
+ };
+ BillingImpl::set_billing(ref state, config);
+
+ // check billing config
+ let billing = BillingImpl::billing(@state);
+ assert(billing.observation_payment_gjuels == 1, 'should be 1');
+ assert(billing.transmission_payment_gjuels == 5, 'should be 5');
+ assert(billing.gas_base == 1, 'should be 1');
+ assert(billing.gas_per_signature == 1, 'should be 1');
+}
+
+#[test]
+fn test_set_billing_config_as_acc_with_access() {
+ let (owner, acc2, billingAccessController, _) = setup();
+ let mut state = STATE();
+ // grant acc2 access on access controller
+ start_cheat_caller_address_global(owner);
+ billingAccessController.add_access(acc2);
+
+ Aggregator::constructor(
+ ref state,
+ owner,
+ contract_address_const::<777>(),
+ 0,
+ 100,
+ billingAccessController.contract_address,
+ 8,
+ 123
+ );
+
+ // set billing config as acc2 with access
+ let config = BillingConfig {
+ observation_payment_gjuels: 1,
+ transmission_payment_gjuels: 5,
+ gas_base: 1,
+ gas_per_signature: 1,
+ };
+ start_cheat_caller_address_global(acc2);
+ BillingImpl::set_billing(ref state, config);
+
+ // check billing config
+ let billing = BillingImpl::billing(@state);
+ assert(billing.observation_payment_gjuels == 1, 'should be 1');
+ assert(billing.transmission_payment_gjuels == 5, 'should be 5');
+ assert(billing.gas_base == 1, 'should be 1');
+ assert(billing.gas_per_signature == 1, 'should be 1');
+}
+
+// --- Payee Management Tests ---
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_set_payees_caller_not_owner() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let payees = array![PayeeConfig { transmitter: acc2, payee: acc2, },];
+ // set payee should revert if caller is not owner
+ start_cheat_caller_address_global(acc2);
+ PayeeManagementImpl::set_payees(ref state, payees);
+}
+
+#[test]
+fn test_set_single_payee() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let payees = array![PayeeConfig { transmitter: acc2, payee: acc2, },];
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+}
+
+#[test]
+fn test_set_multiple_payees() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let payees = array![
+ PayeeConfig { transmitter: acc2, payee: acc2, },
+ PayeeConfig { transmitter: owner, payee: owner, },
+ ];
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+}
+
+#[test]
+#[should_panic(expected: ('only current payee can update',))]
+fn test_transfer_payeeship_caller_not_payee() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let transmitter = contract_address_const::<123>();
+ let payees = array![PayeeConfig { transmitter: transmitter, payee: acc2, },];
+
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+ PayeeManagementImpl::transfer_payeeship(ref state, transmitter, owner);
+}
+
+#[test]
+#[should_panic(expected: ('cannot transfer to self',))]
+fn test_transfer_payeeship_to_self() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let transmitter = contract_address_const::<123>();
+ let payees = array![PayeeConfig { transmitter: transmitter, payee: acc2, },];
+
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+ start_cheat_caller_address_global(acc2);
+ PayeeManagementImpl::transfer_payeeship(ref state, transmitter, acc2);
+}
+
+#[test]
+#[should_panic(expected: ('only proposed payee can accept',))]
+fn test_accept_payeeship_caller_not_proposed_payee() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let transmitter = contract_address_const::<123>();
+ let payees = array![PayeeConfig { transmitter: transmitter, payee: acc2, },];
+
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+ start_cheat_caller_address_global(acc2);
+ PayeeManagementImpl::transfer_payeeship(ref state, transmitter, owner);
+ PayeeManagementImpl::accept_payeeship(ref state, transmitter);
+}
+
+#[test]
+fn test_transfer_and_accept_payeeship() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let transmitter = contract_address_const::<123>();
+ let payees = array![PayeeConfig { transmitter: transmitter, payee: acc2, },];
+
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+ start_cheat_caller_address_global(acc2);
+ PayeeManagementImpl::transfer_payeeship(ref state, transmitter, owner);
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::accept_payeeship(ref state, transmitter);
+}
+// --- Payments and Withdrawals Tests ---
+//
+// NOTE: this test suite largely incomplete as we cannot generate or mock
+// off-chain signatures in cairo-test, and thus cannot generate aggregator rounds.
+// We could explore testing against a mock aggregator contract with the signature
+// verification logic removed in the future.
+
+#[test]
+fn test_owed_payment_no_rounds() {
+ let (owner, acc2, _, _) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(
+ ref state, owner, contract_address_const::<777>(), 0, 100, acc2, 8, 123
+ );
+
+ let transmitter = contract_address_const::<123>();
+ let mut payees = array![PayeeConfig { transmitter: transmitter, payee: acc2, },];
+
+ start_cheat_caller_address_global(owner);
+ PayeeManagementImpl::set_payees(ref state, payees);
+
+ let owed = BillingImpl::owed_payment(@state, transmitter);
+ assert(owed == 0, 'owed payment should be 0');
+}
+
+#[test]
+fn test_link_available_for_payment_no_rounds_or_funds() {
+ let (owner, acc2, _, linkToken) = setup();
+ let mut state = STATE();
+ Aggregator::constructor(ref state, owner, linkToken.contract_address, 0, 100, acc2, 8, 123);
+
+ let (is_negative, diff) = BillingImpl::link_available_for_payment(@state);
+ assert(is_negative == true, 'is_negative should be true');
+ assert(diff == 0, 'absolute_diff should be 0');
+}
diff --git a/contracts/src/tests/test_aggregator_proxy.cairo b/contracts/src/tests/test_aggregator_proxy.cairo
new file mode 100644
index 0000000..d8e6a5b
--- /dev/null
+++ b/contracts/src/tests/test_aggregator_proxy.cairo
@@ -0,0 +1,217 @@
+use starknet::contract_address_const;
+use starknet::ContractAddress;
+use starknet::testing::set_caller_address;
+use starknet::syscalls::deploy_syscall;
+use starknet::class_hash::Felt252TryIntoClassHash;
+use starknet::class_hash::class_hash_const;
+
+use array::ArrayTrait;
+use traits::Into;
+use traits::TryInto;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::ocr2::mocks::mock_aggregator::{
+ MockAggregator, IMockAggregator, IMockAggregatorDispatcher, IMockAggregatorDispatcherTrait
+};
+use plugin::ocr2::aggregator_proxy::AggregatorProxy;
+use plugin::ocr2::aggregator_proxy::AggregatorProxy::{
+ AggregatorProxyImpl, AggregatorProxyInternal, UpgradeableImpl
+};
+use plugin::libraries::access_control::AccessControlComponent::AccessControlImpl;
+use plugin::ocr2::aggregator::Round;
+use plugin::utils::split_felt;
+use plugin::tests::test_ownable::should_implement_ownable;
+use plugin::tests::test_access_controller::should_implement_access_control;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+
+fn STATE() -> AggregatorProxy::ContractState {
+ AggregatorProxy::contract_state_for_testing()
+}
+
+fn setup() -> (
+ ContractAddress,
+ ContractAddress,
+ IMockAggregatorDispatcher,
+ ContractAddress,
+ IMockAggregatorDispatcher
+) {
+ // Set account as default caller
+ let account: ContractAddress = contract_address_const::<1>();
+
+ start_cheat_caller_address_global(account);
+
+ // Deploy mock aggregator 1
+ let mut calldata = ArrayTrait::new();
+ calldata.append(8); // decimals = 8
+
+ let contract_class = declare("MockAggregator").unwrap();
+
+ let (mockAggregatorAddr1, _) = contract_class.deploy(@calldata).unwrap();
+
+ let mockAggregator1 = IMockAggregatorDispatcher { contract_address: mockAggregatorAddr1 };
+
+ // Deploy mock aggregator 2
+ // note: deployment address is deterministic based on deploy_syscall parameters
+ // so we need to change the decimals parameter to avoid an address conflict with mock aggregator 1
+ let mut calldata2 = ArrayTrait::new();
+ calldata2.append(10); // decimals = 10
+
+ let (mockAggregatorAddr2, _) = contract_class.deploy(@calldata).unwrap();
+
+ let mockAggregator2 = IMockAggregatorDispatcher { contract_address: mockAggregatorAddr2 };
+
+ // Return account, mock aggregator address and mock aggregator contract
+ (account, mockAggregatorAddr1, mockAggregator1, mockAggregatorAddr2, mockAggregator2)
+}
+
+#[test]
+fn test_ownable() {
+ let (account, mockAggregatorAddr, _, _, _) = setup();
+ // Deploy aggregator proxy
+ let calldata = array![account.into(), // owner = account
+ mockAggregatorAddr.into(),];
+ let (aggregatorProxyAddr, _) = declare("AggregatorProxy").unwrap().deploy(@calldata).unwrap();
+
+ should_implement_ownable(aggregatorProxyAddr, account);
+}
+
+#[test]
+fn test_access_control() {
+ let (account, mockAggregatorAddr, _, _, _) = setup();
+ // Deploy aggregator proxy
+ let calldata = array![account.into(), // owner = account
+ mockAggregatorAddr.into(),];
+
+ let (aggregatorProxyAddr, _) = declare("AggregatorProxy").unwrap().deploy(@calldata).unwrap();
+
+ should_implement_access_control(aggregatorProxyAddr, account);
+}
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_upgrade_non_owner() {
+ let (_, _, _, _, _) = setup();
+ let mut state = STATE();
+ UpgradeableImpl::upgrade(ref state, class_hash_const::<123>());
+}
+
+fn test_query_latest_round_data() {
+ let (owner, mockAggregatorAddr, mockAggregator, _, _) = setup();
+ let mut state = STATE();
+ // init aggregator proxy with mock aggregator
+ AggregatorProxy::constructor(ref state, owner, mockAggregatorAddr);
+ state.add_access(owner);
+ // insert round into mock aggregator
+ mockAggregator.set_latest_round_data(10, 1, 9, 8);
+ // query latest round
+ let round = AggregatorProxyImpl::latest_round_data(@state);
+ let (phase_id, round_id) = split_felt(round.round_id);
+ assert(phase_id == 1, 'phase_id should be 1');
+ assert(round_id == 1, 'round_id should be 1');
+ assert(round.answer == 10, 'answer should be 10');
+ assert(round.block_num == 1, 'block_num should be 1');
+ assert(round.started_at == 9, 'started_at should be 9');
+ assert(round.updated_at == 8, 'updated_at should be 8');
+
+ // latest_answer matches up with latest_round_data
+ let latest_answer = AggregatorProxyImpl::latest_answer(@state);
+ assert(latest_answer == 10, '(latest) answer should be 10');
+}
+
+#[test]
+#[should_panic(expected: ('user does not have read access',))]
+fn test_query_latest_round_data_without_access() {
+ let (owner, mockAggregatorAddr, mockAggregator, _, _) = setup();
+ let mut state = STATE();
+ // init aggregator proxy with mock aggregator
+ AggregatorProxy::constructor(ref state, owner, mockAggregatorAddr);
+ state.add_access(owner);
+ // insert round into mock aggregator
+ mockAggregator.set_latest_round_data(10, 1, 9, 8);
+ // set caller to non-owner address with no read access
+ start_cheat_caller_address_global(contract_address_const::<2>());
+ // query latest round
+ AggregatorProxyImpl::latest_round_data(@state);
+}
+
+#[test]
+#[should_panic(expected: ('user does not have read access',))]
+fn test_query_latest_answer_without_access() {
+ let (owner, mockAggregatorAddr, mockAggregator, _, _) = setup();
+ let mut state = STATE();
+ // init aggregator proxy with mock aggregator
+ AggregatorProxy::constructor(ref state, owner, mockAggregatorAddr);
+ state.add_access(owner);
+ // insert round into mock aggregator
+ mockAggregator.set_latest_round_data(10, 1, 9, 8);
+ // set caller to non-owner address with no read access
+ start_cheat_caller_address_global(contract_address_const::<2>());
+ // query latest round
+ AggregatorProxyImpl::latest_answer(@state);
+}
+
+#[test]
+fn test_propose_new_aggregator() {
+ let (owner, mockAggregatorAddr1, mockAggregator1, mockAggregatorAddr2, mockAggregator2) =
+ setup();
+ let mut state = STATE();
+ // init aggregator proxy with mock aggregator 1
+ AggregatorProxy::constructor(ref state, owner, mockAggregatorAddr1);
+ state.add_access(owner);
+ // insert rounds into mock aggregators
+ mockAggregator1.set_latest_round_data(10, 1, 9, 8);
+ mockAggregator2.set_latest_round_data(12, 2, 10, 11);
+
+ // propose new mock aggregator to AggregatorProxy
+ AggregatorProxyInternal::propose_aggregator(ref state, mockAggregatorAddr2);
+
+ // latest_round_data should return old aggregator round data
+ let round = AggregatorProxyImpl::latest_round_data(@state);
+ assert(round.answer == 10, 'answer should be 10');
+
+ // mockAggregator2.set_latest_round_data(12, 2, 10, 11);
+
+ // proposed_round_data should return new aggregator round data
+ let proposed_round = AggregatorProxyInternal::proposed_latest_round_data(@state);
+ assert(proposed_round.answer == 12, 'answer should be 12');
+
+ // aggregator should still be set to the old aggregator
+ let aggregator = AggregatorProxyInternal::aggregator(@state);
+ assert(aggregator == mockAggregatorAddr1, 'aggregator should be old addr');
+}
+
+#[test]
+fn test_confirm_new_aggregator() {
+ let (owner, mockAggregatorAddr1, mockAggregator1, mockAggregatorAddr2, mockAggregator2) =
+ setup();
+ let mut state = STATE();
+ // init aggregator proxy with mock aggregator 1
+ AggregatorProxy::constructor(ref state, owner, mockAggregatorAddr1);
+ state.add_access(owner);
+ // insert rounds into mock aggregators
+ mockAggregator1.set_latest_round_data(10, 1, 9, 8);
+ mockAggregator2.set_latest_round_data(12, 2, 10, 11);
+
+ // propose new mock aggregator to AggregatorProxy
+ AggregatorProxyInternal::propose_aggregator(ref state, mockAggregatorAddr2);
+
+ // confirm new mock aggregator
+ AggregatorProxyInternal::confirm_aggregator(ref state, mockAggregatorAddr2);
+
+ // aggregator should be set to the new aggregator
+ let aggregator = AggregatorProxyInternal::aggregator(@state);
+ assert(aggregator == mockAggregatorAddr2, 'aggregator should be new addr');
+
+ // phase ID should be 2
+ let phase_id = AggregatorProxyInternal::phase_id(@state);
+ assert(phase_id == 2, 'phase_id should be 2');
+
+ // latest_round_data should return new aggregator round data
+ let round = AggregatorProxyImpl::latest_round_data(@state);
+ assert(round.answer == 12, 'answer should be 12');
+}
diff --git a/contracts/src/tests/test_erc677.cairo b/contracts/src/tests/test_erc677.cairo
new file mode 100644
index 0000000..6b0fd56
--- /dev/null
+++ b/contracts/src/tests/test_erc677.cairo
@@ -0,0 +1,114 @@
+use starknet::ContractAddress;
+use starknet::contract_address_const;
+use starknet::testing::set_caller_address;
+use starknet::syscalls::deploy_syscall;
+use starknet::class_hash::Felt252TryIntoClassHash;
+
+use array::ArrayTrait;
+use traits::Into;
+use traits::TryInto;
+use zeroable::Zeroable;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::token::mock::valid_erc667_receiver::ValidReceiver;
+use plugin::token::mock::invalid_erc667_receiver::InvalidReceiver;
+use plugin::libraries::token::erc677::ERC677Component;
+use plugin::libraries::token::erc677::ERC677Component::ERC677Impl;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+#[starknet::interface]
+trait MockInvalidReceiver {
+ fn set_supports(ref self: TContractState, value: bool);
+}
+
+use plugin::token::mock::valid_erc667_receiver::{
+ MockValidReceiver, MockValidReceiverDispatcher, MockValidReceiverDispatcherTrait
+};
+
+// Ignored tests are dependent on upgrading our version of cairo to include this PR https://github.com/starkware-libs/cairo/pull/2912/files
+
+fn setup() -> ContractAddress {
+ let account: ContractAddress = contract_address_const::<1>();
+ // Set account as default caller
+ start_cheat_caller_address_global(account);
+ account
+}
+
+fn setup_valid_receiver() -> (ContractAddress, MockValidReceiverDispatcher) {
+ let calldata = ArrayTrait::new();
+
+ let (address, _) = declare("ValidReceiver").unwrap().deploy(@calldata).unwrap();
+
+ let contract = MockValidReceiverDispatcher { contract_address: address };
+ (address, contract)
+}
+
+
+fn setup_invalid_receiver() -> (ContractAddress, MockInvalidReceiverDispatcher) {
+ let calldata = ArrayTrait::new();
+
+ let (address, _) = declare("InvalidReceiver").unwrap().deploy(@calldata).unwrap();
+
+ let contract = MockInvalidReceiverDispatcher { contract_address: address };
+ (address, contract)
+}
+
+type ComponentState =
+ ERC677Component::ComponentState;
+
+fn transfer_and_call(receiver: ContractAddress) {
+ let data = ArrayTrait::::new();
+ // have to send 0 because ERC20 is not initialized with starting supply when using this library by itself
+ let mut state: ComponentState = ERC677Component::component_state_for_testing();
+ state.transfer_and_call(receiver, u256 { high: 0, low: 0 }, data);
+}
+
+#[test]
+#[should_panic(expected: ('ERC20: transfer to 0',))]
+fn test_to_zero_address() {
+ setup();
+ transfer_and_call(Zeroable::zero());
+}
+
+#[test]
+fn test_valid_transfer_and_call() {
+ let sender = setup();
+ let (receiver_address, receiver) = setup_valid_receiver();
+
+ transfer_and_call(receiver_address);
+
+ assert(receiver.verify() == sender, 'on_token_transfer called');
+}
+
+#[test]
+#[should_panic]
+fn test_invalid_receiver_supports_interface_true() {
+ setup();
+ let (receiver_address, receiver) = setup_invalid_receiver();
+
+ receiver.set_supports(true);
+
+ transfer_and_call(receiver_address);
+}
+
+#[test]
+fn test_invalid_receiver_supports_interface_false() {
+ setup();
+ let (receiver_address, _) = setup_invalid_receiver();
+
+ transfer_and_call(receiver_address);
+}
+
+
+#[test]
+#[should_panic]
+fn test_nonexistent_receiver() {
+ setup();
+
+ transfer_and_call(contract_address_const::<777>());
+}
+
diff --git a/contracts/src/tests/test_link_token.cairo b/contracts/src/tests/test_link_token.cairo
new file mode 100644
index 0000000..f1f590c
--- /dev/null
+++ b/contracts/src/tests/test_link_token.cairo
@@ -0,0 +1,153 @@
+use starknet::ContractAddress;
+use starknet::testing::set_caller_address;
+use starknet::contract_address_const;
+use starknet::class_hash::class_hash_const;
+use starknet::class_hash::Felt252TryIntoClassHash;
+use starknet::syscalls::deploy_syscall;
+
+use array::ArrayTrait;
+use traits::Into;
+use traits::TryInto;
+use zeroable::Zeroable;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::token::link_token::LinkToken;
+use plugin::token::link_token::LinkToken::{MintableToken, UpgradeableImpl};
+use openzeppelin::token::erc20::ERC20Component::{ERC20Impl, ERC20MetadataImpl};
+use plugin::tests::test_ownable::should_implement_ownable;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+
+// only tests link token specific functionality
+// erc20 and erc677 functionality is already tested elsewhere
+
+fn STATE() -> LinkToken::ContractState {
+ LinkToken::contract_state_for_testing()
+}
+
+fn setup() -> ContractAddress {
+ let account: ContractAddress = contract_address_const::<1>();
+ // Set account as default caller
+ start_cheat_caller_address_global(account);
+ account
+}
+
+#[test]
+fn test_ownable() {
+ let account = setup();
+ // Deploy PLI token
+ let mut calldata = ArrayTrait::new();
+ calldata.append(class_hash_const::<123>().into()); // minter
+ calldata.append(account.into()); // owner
+
+ let (linkAddr, _) = declare("LinkToken").unwrap().deploy(@calldata).unwrap();
+
+ should_implement_ownable(linkAddr, account);
+}
+
+#[test]
+#[should_panic(expected: ('minter is 0',))]
+fn test_constructor_zero_address() {
+ let sender = setup();
+ let mut state = STATE();
+
+ LinkToken::constructor(ref state, Zeroable::zero(), sender);
+}
+
+#[test]
+fn test_constructor() {
+ let sender = setup();
+ let mut state = STATE();
+ LinkToken::constructor(ref state, sender, sender);
+
+ assert(LinkToken::minter(@state) == sender, 'minter valid');
+ assert(state.erc20.name() == "Plugin Token", 'name valid');
+ assert(state.erc20.symbol() == "PLI", 'symbol valid');
+}
+
+#[test]
+fn test_permissioned_mint_from_minter() {
+ let sender = setup();
+ let mut state = STATE();
+ LinkToken::constructor(ref state, sender, sender);
+ let to = contract_address_const::<908>();
+
+ let zero: felt252 = 0;
+ assert(ERC20Impl::balance_of(@state, sender) == zero.into(), 'zero balance');
+ assert(ERC20Impl::balance_of(@state, to) == zero.into(), 'zero balance');
+
+ let amount: felt252 = 3000;
+ MintableToken::permissioned_mint(ref state, to, amount.into());
+
+ assert(ERC20Impl::balance_of(@state, sender) == zero.into(), 'zero balance');
+ assert(ERC20Impl::balance_of(@state, to) == amount.into(), 'expect balance');
+}
+
+#[test]
+#[should_panic(expected: ('only minter',))]
+fn test_permissioned_mint_from_nonminter() {
+ let sender = setup();
+ let mut state = STATE();
+ let minter = contract_address_const::<111>();
+ LinkToken::constructor(ref state, minter, sender);
+ let to = contract_address_const::<908>();
+
+ let amount: felt252 = 3000;
+ MintableToken::permissioned_mint(ref state, to, amount.into());
+}
+
+#[test]
+#[should_panic(expected: ('u256_sub Overflow',))]
+fn test_permissioned_burn_from_minter() {
+ let zero = 0;
+ let sender = setup();
+ let mut state = STATE();
+ LinkToken::constructor(ref state, sender, sender);
+ let to = contract_address_const::<908>();
+
+ let amount: felt252 = 3000;
+ MintableToken::permissioned_mint(ref state, to, amount.into());
+ assert(ERC20Impl::balance_of(@state, to) == amount.into(), 'expect balance');
+
+ // burn some
+ let burn_amount: felt252 = 2000;
+ let remaining_amount: felt252 = amount - burn_amount;
+ MintableToken::permissioned_burn(ref state, to, burn_amount.into());
+ assert(ERC20Impl::balance_of(@state, to) == remaining_amount.into(), 'remaining balance');
+
+ // burn remaining
+ MintableToken::permissioned_burn(ref state, to, remaining_amount.into());
+ assert(ERC20Impl::balance_of(@state, to) == zero.into(), 'no balance');
+
+ // burn too much
+ MintableToken::permissioned_burn(ref state, to, amount.into());
+}
+
+
+#[test]
+#[should_panic(expected: ('only minter',))]
+fn test_permissioned_burn_from_nonminter() {
+ let sender = setup();
+ let mut state = STATE();
+ let minter = contract_address_const::<111>();
+ LinkToken::constructor(ref state, minter, sender);
+ let to = contract_address_const::<908>();
+
+ let amount: felt252 = 3000;
+ MintableToken::permissioned_burn(ref state, to, amount.into());
+}
+
+#[test]
+#[should_panic(expected: ('Caller is not the owner',))]
+fn test_upgrade_non_owner() {
+ let sender = setup();
+ let mut state = STATE();
+ LinkToken::constructor(ref state, sender, contract_address_const::<111>());
+
+ UpgradeableImpl::upgrade(ref state, class_hash_const::<123>());
+}
+
diff --git a/contracts/src/tests/test_mock_aggregator.cairo b/contracts/src/tests/test_mock_aggregator.cairo
new file mode 100644
index 0000000..29b4a9f
--- /dev/null
+++ b/contracts/src/tests/test_mock_aggregator.cairo
@@ -0,0 +1,69 @@
+use starknet::ContractAddress;
+use starknet::testing::set_caller_address;
+use plugin::ocr2::mocks::mock_aggregator::MockAggregator;
+use starknet::contract_address_const;
+use plugin::ocr2::aggregator::Round;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+fn STATE() -> MockAggregator::ContractState {
+ MockAggregator::contract_state_for_testing()
+}
+
+fn setup() -> ContractAddress {
+ let account: ContractAddress = contract_address_const::<777>();
+ // Set account as default caller
+ start_cheat_caller_address_global(account);
+ account
+}
+
+#[test]
+fn test_deploy() {
+ setup();
+
+ let mut state = STATE();
+
+ MockAggregator::constructor(ref state, 18_u8);
+
+ assert(MockAggregator::Aggregator::decimals(@state) == 18_u8, 'decimals');
+
+ let latest_round = MockAggregator::Aggregator::latest_round_data(@state);
+
+ let _ = Round {
+ round_id: 0, answer: 0_u128, block_num: 0_u64, started_at: 0_u64, updated_at: 0_u64
+ };
+
+ assert(
+ latest_round == Round {
+ round_id: 0, answer: 0_u128, block_num: 0_u64, started_at: 0_u64, updated_at: 0_u64
+ },
+ 'rounds'
+ );
+}
+
+#[test]
+fn test_set_latest_round() {
+ setup();
+
+ let mut state = STATE();
+
+ MockAggregator::constructor(ref state, 18_u8);
+
+ MockAggregator::MockImpl::set_latest_round_data(ref state, 777_u128, 777_u64, 777_u64, 777_u64);
+
+ let expected_round = Round {
+ round_id: 1, answer: 777_u128, block_num: 777_u64, started_at: 777_u64, updated_at: 777_u64
+ };
+
+ assert(
+ MockAggregator::Aggregator::latest_round_data(@state) == expected_round, 'round not equal'
+ );
+
+ assert(
+ MockAggregator::Aggregator::latest_answer(@state) == expected_round.answer,
+ 'latest answer not equal'
+ );
+}
+
diff --git a/contracts/src/tests/test_multisig.cairo b/contracts/src/tests/test_multisig.cairo
new file mode 100644
index 0000000..1fa41db
--- /dev/null
+++ b/contracts/src/tests/test_multisig.cairo
@@ -0,0 +1,676 @@
+use plugin::multisig::IMultisigDispatcherTrait;
+use core::traits::Into;
+use starknet::class_hash_const;
+use starknet::contract_address_const;
+use starknet::syscalls::deploy_syscall;
+use starknet::testing::set_caller_address;
+use starknet::testing::set_contract_address;
+use starknet::Felt252TryIntoClassHash;
+
+use array::ArrayTrait;
+use option::OptionTrait;
+use result::ResultTrait;
+use traits::TryInto;
+
+use plugin::multisig::assert_unique_values;
+use plugin::multisig::Multisig;
+use plugin::multisig::Multisig::{MultisigImpl, UpgradeableImpl};
+use plugin::multisig::{IMultisigDispatcher};
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global,
+ stop_cheat_caller_address_global, cheat_caller_address, CheatSpan
+};
+
+fn STATE() -> Multisig::ContractState {
+ Multisig::contract_state_for_testing()
+}
+
+fn sample_calldata() -> Array:: {
+ array![1, 2, 32]
+}
+
+#[test]
+fn test_assert_unique_values_empty() {
+ let a = ArrayTrait::::new();
+ assert_unique_values(@a);
+}
+
+#[test]
+fn test_assert_unique_values_no_duplicates() {
+ let a = array![1, 2, 3];
+ assert_unique_values(@a);
+}
+
+#[test]
+#[should_panic]
+fn test_assert_unique_values_with_duplicate() {
+ let a = array![1, 2, 3, 3];
+ assert_unique_values(@a);
+}
+
+#[test]
+fn test_is_signer_true() {
+ let mut state = STATE();
+ let signer = contract_address_const::<1>();
+ let mut signers = ArrayTrait::new();
+ signers.append(signer);
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ assert(MultisigImpl::is_signer(@state, signer), 'should be signer');
+}
+
+#[test]
+fn test_is_signer_false() {
+ let mut state = STATE();
+ let not_signer = contract_address_const::<2>();
+ let mut signers = ArrayTrait::new();
+ signers.append(contract_address_const::<1>());
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ assert(!MultisigImpl::is_signer(@state, not_signer), 'should be signer');
+}
+
+#[test]
+fn test_signer_len() {
+ let mut state = STATE();
+ let mut signers = ArrayTrait::new();
+ signers.append(contract_address_const::<1>());
+ signers.append(contract_address_const::<2>());
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ assert(MultisigImpl::get_signers_len(@state) == 2, 'should equal 2 signers');
+}
+
+#[test]
+fn test_get_signers() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ let returned_signers = MultisigImpl::get_signers(@state);
+ assert(returned_signers.len() == 2, 'should match signers length');
+ assert(*returned_signers.at(0) == signer1, 'should match signer 1');
+ assert(*returned_signers.at(1) == signer2, 'should match signer 2');
+}
+
+#[test]
+fn test_get_threshold() {
+ let mut state = STATE();
+ let mut signers = ArrayTrait::new();
+ signers.append(contract_address_const::<1>());
+ signers.append(contract_address_const::<2>());
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ assert(MultisigImpl::get_threshold(@state) == 1, 'should equal threshold of 1');
+}
+
+#[test]
+fn test_submit_transaction() {
+ let mut state = STATE();
+ let signer = contract_address_const::<1>();
+ let signers = array![signer];
+ Multisig::constructor(ref state, :signers, threshold: 1);
+
+ start_cheat_caller_address_global(signer);
+ let to = contract_address_const::<42>();
+ let function_selector = 10;
+ MultisigImpl::submit_transaction(
+ ref state, :to, :function_selector, calldata: sample_calldata()
+ );
+
+ let (transaction, _) = MultisigImpl::get_transaction(@state, 0);
+ assert(transaction.to == to, 'should match target address');
+ assert(transaction.function_selector == function_selector, 'should match function selector');
+ assert(transaction.calldata_len == sample_calldata().len(), 'should match calldata length');
+ assert(!transaction.executed, 'should not be executed');
+ assert(transaction.confirmations == 0, 'should not have confirmations');
+// TODO: compare calldata when loops are supported
+}
+
+#[test]
+#[should_panic]
+fn test_submit_transaction_not_signer() {
+ let mut state = STATE();
+ let signer = contract_address_const::<1>();
+ let signers = array![signer];
+ Multisig::constructor(ref state, :signers, threshold: 1);
+
+ start_cheat_caller_address_global(contract_address_const::<3>());
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+}
+
+#[test]
+fn test_confirm_transaction() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+ Multisig::constructor(ref state, :signers, threshold: 2);
+
+ start_cheat_caller_address_global(signer1);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+
+ assert(MultisigImpl::is_confirmed(@state, nonce: 0, signer: signer1), 'should be confirmed');
+ assert(
+ !MultisigImpl::is_confirmed(@state, nonce: 0, signer: signer2), 'should not be confirmed'
+ );
+ let (transaction, _) = MultisigImpl::get_transaction(@state, 0);
+ assert(transaction.confirmations == 1, 'should have confirmation');
+}
+
+#[test]
+#[should_panic]
+fn test_confirm_transaction_not_signer() {
+ let mut state = STATE();
+ let signer = contract_address_const::<1>();
+ let not_signer = contract_address_const::<2>();
+ let signers = array![signer];
+ Multisig::constructor(ref state, :signers, threshold: 1);
+ start_cheat_caller_address_global(signer);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ start_cheat_caller_address_global(not_signer);
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+}
+
+#[test]
+fn test_revoke_confirmation() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+ Multisig::constructor(ref state, :signers, threshold: 2);
+ start_cheat_caller_address_global(signer1);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+
+ MultisigImpl::revoke_confirmation(ref state, nonce: 0);
+
+ assert(
+ !MultisigImpl::is_confirmed(@state, nonce: 0, signer: signer1), 'should not be confirmed'
+ );
+ assert(
+ !MultisigImpl::is_confirmed(@state, nonce: 0, signer: signer2), 'should not be confirmed'
+ );
+ let (transaction, _) = MultisigImpl::get_transaction(@state, 0);
+ assert(transaction.confirmations == 0, 'should not have confirmation');
+}
+
+#[test]
+#[should_panic]
+fn test_revoke_confirmation_not_signer() {
+ let mut state = STATE();
+ let signer = contract_address_const::<1>();
+ let not_signer = contract_address_const::<2>();
+ let mut signers = array![signer];
+ Multisig::constructor(ref state, :signers, threshold: 2);
+ start_cheat_caller_address_global(signer);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+ start_cheat_caller_address_global(not_signer);
+ MultisigImpl::revoke_confirmation(ref state, nonce: 0);
+}
+
+#[test]
+#[should_panic]
+fn test_execute_confirmation_below_threshold() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+
+ Multisig::constructor(ref state, :signers, threshold: 2);
+ start_cheat_caller_address_global(signer1);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+ MultisigImpl::execute_transaction(ref state, nonce: 0);
+}
+
+#[test]
+#[should_panic(expected: ('only multisig allowed',))]
+fn test_upgrade_not_multisig() {
+ let mut state = STATE();
+ let account = contract_address_const::<777>();
+ start_cheat_caller_address_global(account);
+ UpgradeableImpl::upgrade(ref state, class_hash_const::<1>())
+}
+
+#[test]
+fn test_execute() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+ Multisig::constructor(ref state, :signers, threshold: 2);
+
+ let calldata = ArrayTrait::new();
+
+ let (test_address, _) = declare("MockMultisigTarget").unwrap().deploy(@calldata).unwrap();
+
+ start_cheat_caller_address_global(signer1);
+ let increment_calldata = array![42, 100];
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: test_address,
+ // increment()
+ function_selector: 0x7a44dde9fea32737a5cf3f9683b3235138654aa2d189f6fe44af37a61dc60d,
+ calldata: increment_calldata,
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+ start_cheat_caller_address_global(signer2);
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+
+ let response = MultisigImpl::execute_transaction(ref state, nonce: 0);
+ assert(response.len() == 3, 'expected response length 3');
+ assert(*response.at(0) == 2, 'expected array length 2');
+ assert(*response.at(1) == 43, 'expected array value 43');
+ assert(*response.at(2) == 101, 'expected array value 101');
+}
+
+#[test]
+#[should_panic(expected: ('invalid signer',))]
+fn test_execute_not_signer() {
+ let mut state = STATE();
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+ Multisig::constructor(ref state, :signers, threshold: 2);
+ start_cheat_caller_address_global(signer1);
+ MultisigImpl::submit_transaction(
+ ref state,
+ to: contract_address_const::<42>(),
+ function_selector: 10,
+ calldata: sample_calldata(),
+ );
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+ start_cheat_caller_address_global(signer2);
+ MultisigImpl::confirm_transaction(ref state, nonce: 0);
+ start_cheat_caller_address_global(contract_address_const::<3>());
+ MultisigImpl::execute_transaction(ref state, nonce: 0);
+}
+
+#[test]
+#[should_panic(expected: ('transaction invalid',))]
+fn test_execute_after_set_signers() {
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signer3 = contract_address_const::<3>();
+ let signers = array![signer1, signer2];
+ let init_threshold: usize = 2;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ start_cheat_caller_address_global(signer1);
+ multisig
+ .submit_transaction(
+ to: contract_address_const::<42>(), function_selector: 10, calldata: sample_calldata(),
+ );
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(signer2);
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(multisig_address);
+ let new_signers = array![signer2, signer3];
+ multisig.set_signers(new_signers);
+ start_cheat_caller_address_global(signer2);
+ multisig.execute_transaction(nonce: 0);
+}
+
+#[test]
+#[should_panic(expected: ('transaction invalid',))]
+fn test_execute_after_set_signers_and_threshold() {
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signer3 = contract_address_const::<3>();
+ let signers = array![signer1, signer2];
+ let init_threshold: usize = 2;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ // Multisig::constructor(ref state, :signers, threshold: 2);
+ start_cheat_caller_address_global(signer1);
+ multisig
+ .submit_transaction(
+ to: contract_address_const::<42>(), function_selector: 10, calldata: sample_calldata(),
+ );
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(signer2);
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(multisig_address);
+ let new_signers = array![signer2, signer3];
+ multisig.set_signers_and_threshold(new_signers, 1);
+ start_cheat_caller_address_global(signer2);
+ multisig.execute_transaction(nonce: 0);
+}
+
+#[test]
+#[should_panic(expected: ('transaction invalid',))]
+fn test_execute_after_set_threshold() {
+ let signer1 = contract_address_const::<1>();
+ let signer2 = contract_address_const::<2>();
+ let signers = array![signer1, signer2];
+ let init_threshold: usize = 2;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ start_cheat_caller_address_global(signer1);
+ multisig
+ .submit_transaction(
+ to: contract_address_const::<42>(), function_selector: 10, calldata: sample_calldata(),
+ );
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(signer2);
+ multisig.confirm_transaction(nonce: 0);
+ start_cheat_caller_address_global(multisig_address);
+ multisig.set_threshold(1);
+ start_cheat_caller_address_global(signer1);
+ multisig.execute_transaction(nonce: 0);
+}
+
+// test set_threshold (non-recursive)
+#[test]
+fn test_set_threshold() {
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let s3 = contract_address_const::<3>();
+ let signers = array![s1, s2, s3];
+ let init_threshold: usize = 3;
+ let new_threshold: usize = 2;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+ assert(multisig.get_threshold() == init_threshold, 'invalid init threshold');
+ start_cheat_caller_address_global(multisig_address);
+ multisig.set_threshold(new_threshold);
+ assert(multisig.get_threshold() == new_threshold, 'threshold was not updated');
+}
+
+// test set_threshold with recursive call
+#[test]
+fn test_recursive_set_threshold() {
+ // Defines helper variables
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let signers = array![s1, s2];
+ let init_threshold: usize = 2;
+ let new_threshold: usize = 1;
+
+ // Deploys the contract
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ // Gets a dispatcher (so we can call methods on the deployed contract)
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ // Checks that the threshold was correctly initialized on deployment
+ assert(multisig.get_threshold() == init_threshold, 'invalid init threshold');
+ // Recursive call occurs here - this code proposes a transaction to the
+ // multisig contract that calls the set_threshold function on the multisig
+ // contract.
+ let mut set_threshold_calldata = ArrayTrait::new();
+ Serde::serialize(@new_threshold, ref set_threshold_calldata);
+ start_cheat_caller_address_global(s1);
+ multisig
+ .submit_transaction(multisig_address, selector!("set_threshold"), set_threshold_calldata);
+ // Signer 1 confirms the transaction
+ start_cheat_caller_address_global(s1);
+ multisig.confirm_transaction(0);
+
+ // Signer 2 confirms the transaction
+ start_cheat_caller_address_global(s2);
+ multisig.confirm_transaction(0);
+
+ // Once we have enough confirmations, we execute the transaction
+ // cheat only once because we want the multisig to execute the recursive tx
+ cheat_caller_address(multisig_address, s1, CheatSpan::TargetCalls(1));
+
+ multisig.execute_transaction(0);
+
+ // Now we check that the threshold was actually updated
+ assert(multisig.get_threshold() == new_threshold, 'threshold was not updated');
+}
+
+// test set_signers (non-recursive)
+#[test]
+fn test_set_signers() {
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let init_signers = array![s1, s2];
+ let new_signers = array![s1];
+ let threshold: usize = 2;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@init_signers, ref deploy_calldata);
+ Serde::serialize(@threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ let returned_signers = multisig.get_signers();
+ assert(returned_signers.len() == 2, 'should match signers length');
+ assert(*returned_signers.at(0) == s1, 'should match signer 1');
+ assert(*returned_signers.at(1) == s2, 'should match signer 2');
+ assert(multisig.get_threshold() == 2, 'wrong init threshold');
+
+ start_cheat_caller_address_global(multisig_address);
+ multisig.set_signers(new_signers);
+
+ let updated_signers = multisig.get_signers();
+ assert(updated_signers.len() == 1, 'should match signers length');
+ assert(*updated_signers.at(0) == s1, 'should match signer 1');
+ assert(multisig.get_threshold() == 1, 'threshold not updated');
+}
+
+// test set_signers with recursive call
+#[test]
+fn test_recursive_set_signers() {
+ // Defines helper variables
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let init_signers = array![s1, s2];
+ let new_signers = array![s1];
+ let init_threshold: usize = 2;
+
+ // Deploys the contract
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@init_signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ // Gets a dispatcher (so we can call methods on the deployed contract)
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ // Checks that the signers were correctly initialized on deployment
+ let returned_signers = multisig.get_signers();
+ assert(returned_signers.len() == 2, 'should match signers length');
+ assert(*returned_signers.at(0) == s1, 'should match signer 1');
+ assert(*returned_signers.at(1) == s2, 'should match signer 2');
+ assert(multisig.get_threshold() == 2, 'wrong init threshold');
+
+ // Recursive call occurs here - this code proposes a transaction to the
+ // multisig contract that calls the set_signers function on the multisig
+ // contract.
+ let mut set_signers_calldata = ArrayTrait::new();
+ Serde::serialize(@new_signers, ref set_signers_calldata);
+ start_cheat_caller_address_global(s1);
+ multisig.submit_transaction(multisig_address, selector!("set_signers"), set_signers_calldata);
+
+ // Signer 1 confirms the transaction
+ start_cheat_caller_address_global(s1);
+ multisig.confirm_transaction(0);
+
+ // Signer 2 confirms the transaction
+ start_cheat_caller_address_global(s2);
+ multisig.confirm_transaction(0);
+
+ // Once we have enough confirmations, we execute the transaction
+ cheat_caller_address(multisig_address, s1, CheatSpan::TargetCalls(1));
+ multisig.execute_transaction(0);
+
+ // Now we check that the signers were actually updated
+ let updated_signers = multisig.get_signers();
+ assert(updated_signers.len() == 1, 'should match signers length');
+ assert(*updated_signers.at(0) == s1, 'should match signer 1');
+ assert(multisig.get_threshold() == 1, 'wrong threshold');
+}
+
+// test set_signers_and_threshold (non-recursive)
+#[test]
+fn test_set_signers_and_threshold() {
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let s3 = contract_address_const::<3>();
+ let init_signers = array![s1, s2, s3];
+ let new_signers = array![s1, s2];
+ let init_threshold: usize = 3;
+ let new_threshold: usize = 1;
+
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@init_signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ let returned_signers = multisig.get_signers();
+ assert(returned_signers.len() == 3, 'should match signers length');
+ assert(*returned_signers.at(0) == s1, 'should match signer 1');
+ assert(*returned_signers.at(1) == s2, 'should match signer 2');
+ assert(*returned_signers.at(2) == s3, 'should match signer 3');
+ assert(multisig.get_threshold() == init_threshold, 'wrong init threshold');
+
+ start_cheat_caller_address_global(multisig_address);
+ multisig.set_signers_and_threshold(new_signers, new_threshold);
+
+ let updated_signers = multisig.get_signers();
+ assert(updated_signers.len() == 2, 'should match signers length');
+ assert(*updated_signers.at(0) == s1, 'should match signer 1');
+ assert(*updated_signers.at(1) == s2, 'should match signer 2');
+ assert(multisig.get_threshold() == new_threshold, 'threshold not updated');
+}
+
+// test set_signers_and_threshold with recursive call
+#[test]
+fn test_recursive_set_signers_and_threshold() {
+ // Defines helper variables
+ let s1 = contract_address_const::<1>();
+ let s2 = contract_address_const::<2>();
+ let s3 = contract_address_const::<3>();
+ let init_signers = array![s1, s2, s3];
+ let new_signers = array![s1, s2];
+ let init_threshold: usize = 3;
+ let new_threshold: usize = 1;
+
+ // Deploys the contract
+ let mut deploy_calldata = ArrayTrait::new();
+ Serde::serialize(@init_signers, ref deploy_calldata);
+ Serde::serialize(@init_threshold, ref deploy_calldata);
+
+ let (multisig_address, _) = declare("Multisig").unwrap().deploy(@deploy_calldata).unwrap();
+
+ // Gets a dispatcher (so we can call methods on the deployed contract)
+ let multisig = IMultisigDispatcher { contract_address: multisig_address };
+
+ // Checks that the initial state is correct
+ let returned_signers = multisig.get_signers();
+ assert(returned_signers.len() == 3, 'should match signers length');
+ assert(*returned_signers.at(0) == s1, 'should match signer 1');
+ assert(*returned_signers.at(1) == s2, 'should match signer 2');
+ assert(*returned_signers.at(2) == s3, 'should match signer 3');
+ assert(multisig.get_threshold() == 3, 'wrong init threshold');
+
+ // Recursive call occurs here - this code proposes a transaction to the
+ // multisig contract that calls the set_signers_and_threshold function
+ // on the multisig contract.
+ let mut set_signers_and_threshold_calldata = ArrayTrait::new();
+ Serde::serialize(@new_signers, ref set_signers_and_threshold_calldata);
+ Serde::serialize(@new_threshold, ref set_signers_and_threshold_calldata);
+ start_cheat_caller_address_global(s1);
+ multisig
+ .submit_transaction(
+ multisig_address,
+ selector!("set_signers_and_threshold"),
+ set_signers_and_threshold_calldata
+ );
+
+ // Signer 1 confirms the transaction
+ start_cheat_caller_address_global(s1);
+ multisig.confirm_transaction(0);
+
+ // Signer 2 confirms the transaction
+ start_cheat_caller_address_global(s2);
+ multisig.confirm_transaction(0);
+
+ // Signer 3 confirms the transaction
+ start_cheat_caller_address_global(s3);
+ multisig.confirm_transaction(0);
+
+ // Once we have enough confirmations, we execute the transaction
+ cheat_caller_address(multisig_address, s1, CheatSpan::TargetCalls(1));
+ multisig.execute_transaction(0);
+
+ // Now we check that the signers were actually updated
+ let updated_signers = multisig.get_signers();
+ assert(updated_signers.len() == 2, 'should match signers length');
+ assert(*updated_signers.at(0) == s1, 'should match signer 1');
+ assert(*updated_signers.at(1) == s2, 'should match signer 2');
+ assert(multisig.get_threshold() == 1, 'wrong threshold');
+}
+
diff --git a/contracts/src/tests/test_ownable.cairo b/contracts/src/tests/test_ownable.cairo
new file mode 100644
index 0000000..d898bbb
--- /dev/null
+++ b/contracts/src/tests/test_ownable.cairo
@@ -0,0 +1,42 @@
+use starknet::contract_address_const;
+use starknet::ContractAddress;
+use starknet::testing::set_caller_address;
+use starknet::testing::set_contract_address;
+use zeroable::Zeroable;
+
+use openzeppelin::access::ownable::interface::{
+ IOwnableTwoStep, IOwnableTwoStepDispatcher, IOwnableTwoStepDispatcherTrait
+};
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+//
+// General ownable contract tests
+//
+
+fn should_implement_ownable(contract_addr: ContractAddress, owner: ContractAddress) {
+ let contract = IOwnableTwoStepDispatcher { contract_address: contract_addr };
+ let acc2: ContractAddress = contract_address_const::<2222>();
+
+ // check owner is set correctly
+ assert(owner == contract.owner(), 'owner does not match');
+
+ // transfer ownership - check owner unchanged and proposed owner set correctly
+ start_cheat_caller_address_global(owner);
+ contract.transfer_ownership(acc2);
+ assert(owner == contract.owner(), 'owner should remain unchanged');
+ assert(acc2 == contract.pending_owner(), 'acc2 should be proposed owner');
+
+ // accept ownership - check owner changed and proposed owner set to zero
+ start_cheat_caller_address_global(acc2);
+ contract.accept_ownership();
+ assert(contract.owner() == acc2, 'failed to change ownership');
+ assert(contract.pending_owner().is_zero(), 'proposed owner should be zero');
+
+ // renounce ownership
+ contract.renounce_ownership();
+ assert(contract.owner().is_zero(), 'owner not 0 after renounce');
+}
+
diff --git a/contracts/src/tests/test_sequencer_uptime_feed.cairo b/contracts/src/tests/test_sequencer_uptime_feed.cairo
new file mode 100644
index 0000000..77d652d
--- /dev/null
+++ b/contracts/src/tests/test_sequencer_uptime_feed.cairo
@@ -0,0 +1,134 @@
+use starknet::ContractAddress;
+use starknet::EthAddress;
+use starknet::contract_address_const;
+use starknet::class_hash::class_hash_const;
+use starknet::class_hash::Felt252TryIntoClassHash;
+use starknet::syscalls::deploy_syscall;
+use starknet::testing::set_caller_address;
+use starknet::testing::set_contract_address;
+
+use array::ArrayTrait;
+use traits::Into;
+use traits::TryInto;
+use option::OptionTrait;
+use core::result::ResultTrait;
+
+use plugin::emergency::sequencer_uptime_feed::SequencerUptimeFeed;
+use plugin::libraries::access_control::{
+ IAccessController, IAccessControllerDispatcher, IAccessControllerDispatcherTrait
+};
+use plugin::ocr2::aggregator_proxy::{
+ IAggregatorProxy, IAggregatorProxyDispatcher, IAggregatorProxyDispatcherTrait
+};
+use plugin::ocr2::aggregator_proxy::AggregatorProxy;
+use plugin::ocr2::aggregator_proxy::AggregatorProxy::AggregatorProxyImpl;
+use plugin::tests::test_ownable::should_implement_ownable;
+use plugin::tests::test_access_controller::should_implement_access_control;
+
+use plugin::emergency::sequencer_uptime_feed::{
+ ISequencerUptimeFeed, ISequencerUptimeFeedDispatcher, ISequencerUptimeFeedDispatcherTrait
+};
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+
+fn PROXY() -> AggregatorProxy::ContractState {
+ AggregatorProxy::contract_state_for_testing()
+}
+
+fn STATE() -> SequencerUptimeFeed::ContractState {
+ SequencerUptimeFeed::contract_state_for_testing()
+}
+
+fn setup() -> (ContractAddress, ContractAddress, ISequencerUptimeFeedDispatcher) {
+ let account: ContractAddress = contract_address_const::<777>();
+
+ start_cheat_caller_address_global(account);
+
+ // Deploy seqeuencer uptime feed
+ let calldata = array![0, // initial status
+ account.into() // owner
+ ];
+
+ let (sequencerFeedAddr, _) = declare("SequencerUptimeFeed").unwrap().deploy(@calldata).unwrap();
+
+ let sequencerUptimeFeed = ISequencerUptimeFeedDispatcher {
+ contract_address: sequencerFeedAddr
+ };
+
+ (account, sequencerFeedAddr, sequencerUptimeFeed)
+}
+
+#[test]
+fn test_ownable() {
+ let (account, sequencerFeedAddr, _) = setup();
+ should_implement_ownable(sequencerFeedAddr, account);
+}
+
+#[test]
+fn test_access_control() {
+ let (account, sequencerFeedAddr, _) = setup();
+ should_implement_access_control(sequencerFeedAddr, account);
+}
+
+#[test]
+#[should_panic()]
+fn test_set_l1_sender_not_owner() {
+ let (_, _, sequencerUptimeFeed) = setup();
+ start_cheat_caller_address_global(contract_address_const::<111>());
+ sequencerUptimeFeed.set_l1_sender(EthAddress { address: 789 });
+}
+
+#[test]
+fn test_set_l1_sender() {
+ let (owner, _, sequencerUptimeFeed) = setup();
+ start_cheat_caller_address_global(owner);
+ sequencerUptimeFeed.set_l1_sender(EthAddress { address: 789 });
+ assert(sequencerUptimeFeed.l1_sender().address == 789, 'l1_sender should be set to 789');
+}
+
+#[test]
+#[should_panic(expected: ('user does not have read access',))]
+fn test_latest_round_data_no_access() {
+ let (owner, sequencerFeedAddr, _) = setup();
+ let mut proxy = PROXY();
+ AggregatorProxy::constructor(ref proxy, owner, sequencerFeedAddr);
+ AggregatorProxyImpl::latest_round_data(@proxy);
+}
+
+#[test]
+#[should_panic(expected: ('user does not have read access',))]
+fn test_latest_answer_no_access() {
+ let (owner, sequencerFeedAddr, _) = setup();
+ let mut proxy = PROXY();
+ AggregatorProxy::constructor(ref proxy, owner, sequencerFeedAddr);
+ AggregatorProxyImpl::latest_answer(@proxy);
+}
+
+#[test]
+fn test_aggregator_proxy_response() {
+ let (owner, sequencerFeedAddr, _) = setup();
+ start_cheat_caller_address_global(owner);
+ let contract = IAccessControllerDispatcher { contract_address: sequencerFeedAddr };
+ contract.add_access(owner);
+
+ let proxy = IAggregatorProxyDispatcher { contract_address: sequencerFeedAddr };
+
+ // latest round data
+ let latest_round_data = proxy.latest_round_data();
+ assert(latest_round_data.answer == 0, 'latest_round_data should be 0');
+
+ // latest answer
+ let latest_answer = proxy.latest_answer();
+ assert(latest_answer == 0, 'latest_answer should be 0');
+
+ // description
+ let description = proxy.description();
+ assert(description == 'L2 Sequencer Uptime Status Feed', 'description does not match');
+
+ // decimals
+ let decimals = proxy.decimals();
+ assert(decimals == 0, 'decimals should be 0');
+}
diff --git a/contracts/src/tests/test_upgradeable.cairo b/contracts/src/tests/test_upgradeable.cairo
new file mode 100644
index 0000000..6bb4c69
--- /dev/null
+++ b/contracts/src/tests/test_upgradeable.cairo
@@ -0,0 +1,57 @@
+use traits::Into;
+
+use starknet::testing::set_caller_address;
+use starknet::ContractAddress;
+use starknet::contract_address_const;
+use starknet::class_hash::class_hash_const;
+use starknet::syscalls::deploy_syscall;
+
+use plugin::libraries::upgradeable::Upgradeable;
+use plugin::libraries::mocks::mock_upgradeable::{
+ MockUpgradeable, IMockUpgradeableDispatcher, IMockUpgradeableDispatcherTrait,
+ IMockUpgradeableDispatcherImpl
+};
+use plugin::libraries::mocks::mock_non_upgradeable::{
+ MockNonUpgradeable, IMockNonUpgradeableDispatcher, IMockNonUpgradeableDispatcherTrait,
+ IMockNonUpgradeableDispatcherImpl
+};
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+
+fn setup() -> ContractAddress {
+ let account: ContractAddress = contract_address_const::<777>();
+ start_cheat_caller_address_global(account);
+ account
+}
+
+#[test]
+fn test_upgrade_and_call() {
+ let _ = setup();
+
+ let calldata = array![];
+
+ let (contractAddr, _) = declare("MockUpgradeable").unwrap().deploy(@calldata).unwrap();
+
+ let mockUpgradeable = IMockUpgradeableDispatcher { contract_address: contractAddr };
+ assert(mockUpgradeable.foo() == true, 'should call foo');
+
+ let contract_class = declare("MockNonUpgradeable").unwrap();
+
+ mockUpgradeable.upgrade(contract_class.class_hash);
+
+ // now, contract should be different
+ let mockNonUpgradeable = IMockNonUpgradeableDispatcher { contract_address: contractAddr };
+ assert(mockNonUpgradeable.bar() == true, 'should call bar');
+}
+
+
+#[test]
+#[should_panic(expected: ('Class hash cannot be zero',))]
+fn test_upgrade_zero_hash() {
+ let _ = setup();
+
+ Upgradeable::upgrade(class_hash_const::<0>());
+}
diff --git a/contracts/src/token.cairo b/contracts/src/token.cairo
new file mode 100644
index 0000000..1c56c11
--- /dev/null
+++ b/contracts/src/token.cairo
@@ -0,0 +1,2 @@
+mod link_token;
+mod mock;
diff --git a/contracts/src/token/link_token.cairo b/contracts/src/token/link_token.cairo
new file mode 100644
index 0000000..756236f
--- /dev/null
+++ b/contracts/src/token/link_token.cairo
@@ -0,0 +1,131 @@
+use starknet::ContractAddress;
+
+// https://github.com/starknet-io/starkgate-contracts/blob/v2.0/src/cairo/mintable_token_interface.cairo
+#[starknet::interface]
+trait IMintableToken {
+ fn permissioned_mint(ref self: TContractState, account: ContractAddress, amount: u256);
+ fn permissioned_burn(ref self: TContractState, account: ContractAddress, amount: u256);
+}
+
+#[starknet::contract]
+mod LinkToken {
+ use starknet::ContractAddress;
+ use starknet::class_hash::ClassHash;
+
+ use zeroable::Zeroable;
+
+ use openzeppelin::token::erc20::ERC20Component;
+ use openzeppelin::access::ownable::OwnableComponent;
+
+ use super::IMintableToken;
+ use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
+ use plugin::libraries::token::erc677::ERC677Component;
+ use plugin::libraries::type_and_version::ITypeAndVersion;
+ use plugin::libraries::upgradeable::{Upgradeable, IUpgradeable};
+
+ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
+ component!(path: ERC20Component, storage: erc20, event: ERC20Event);
+ component!(path: ERC677Component, storage: erc677, event: ERC677Event);
+
+ #[abi(embed_v0)]
+ impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl;
+ impl InternalImpl = OwnableComponent::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl ERC20Impl = ERC20Component::ERC20Impl;
+ #[abi(embed_v0)]
+ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;
+ impl ERC20InternalImpl = ERC20Component::InternalImpl;
+
+ #[abi(embed_v0)]
+ impl ERC677Impl = ERC677Component::ERC677Impl;
+
+ #[storage]
+ struct Storage {
+ #[substorage(v0)]
+ ownable: OwnableComponent::Storage,
+ _minter: ContractAddress,
+ #[substorage(v0)]
+ erc20: ERC20Component::Storage,
+ #[substorage(v0)]
+ erc677: ERC677Component::Storage
+ }
+
+ #[event]
+ #[derive(Drop, starknet::Event)]
+ enum Event {
+ #[flat]
+ OwnableEvent: OwnableComponent::Event,
+ #[flat]
+ ERC20Event: ERC20Component::Event,
+ #[flat]
+ ERC677Event: ERC677Component::Event
+ }
+
+ //
+ // IMintableToken (StarkGate)
+ //
+ #[abi(embed_v0)]
+ impl MintableToken of IMintableToken {
+ fn permissioned_mint(ref self: ContractState, account: ContractAddress, amount: u256) {
+ only_minter(@self);
+ self.erc20._mint(account, amount);
+ }
+
+ fn permissioned_burn(ref self: ContractState, account: ContractAddress, amount: u256) {
+ only_minter(@self);
+ self.erc20._burn(account, amount);
+ }
+ }
+
+
+ #[constructor]
+ fn constructor(ref self: ContractState, minter: ContractAddress, owner: ContractAddress) {
+ let name = "Plugin Token";
+ let symbol = "PLI";
+ self.erc20.initializer(name, symbol);
+ assert(!minter.is_zero(), 'minter is 0');
+ self._minter.write(minter);
+ self.ownable.initializer(owner);
+ }
+
+ // TODO #[view]
+ fn minter(self: @ContractState) -> ContractAddress {
+ self._minter.read()
+ }
+
+ #[abi(embed_v0)]
+ impl TypeAndVersionImpl of ITypeAndVersion {
+ fn type_and_version(self: @ContractState) -> felt252 {
+ 'LinkToken 1.0.0'
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl UpgradeableImpl of IUpgradeable {
+ fn upgrade(ref self: ContractState, new_impl: ClassHash) {
+ self.ownable.assert_only_owner();
+ Upgradeable::upgrade(new_impl)
+ }
+ }
+
+ // fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {
+ // let mut state = ERC20::unsafe_new_contract_state();
+ // ERC20::ERC20Impl::increase_allowance(ref state, spender, added_value)
+ // }
+
+ // fn decrease_allowance(ref self: ContractState, spender: ContractAddress, subtracted_value: u256) -> bool {
+ // let mut state = ERC20::unsafe_new_contract_state();
+ // ERC20::ERC20Impl::decrease_allowance(ref state, spender, subtracted_value)
+ // }
+
+ //
+ // Internal
+ //
+
+ fn only_minter(self: @ContractState) {
+ let caller = starknet::get_caller_address();
+ let minter = self._minter.read();
+ assert(caller == minter, 'only minter');
+ }
+}
diff --git a/contracts/src/token/mock.cairo b/contracts/src/token/mock.cairo
new file mode 100644
index 0000000..dd1f804
--- /dev/null
+++ b/contracts/src/token/mock.cairo
@@ -0,0 +1,2 @@
+mod valid_erc667_receiver;
+mod invalid_erc667_receiver;
diff --git a/contracts/src/token/mock/invalid_erc667_receiver.cairo b/contracts/src/token/mock/invalid_erc667_receiver.cairo
new file mode 100644
index 0000000..9332dc6
--- /dev/null
+++ b/contracts/src/token/mock/invalid_erc667_receiver.cairo
@@ -0,0 +1,25 @@
+#[starknet::contract]
+mod InvalidReceiver {
+ #[storage]
+ struct Storage {
+ _supports: bool
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {}
+
+ #[abi(per_item)]
+ #[generate_trait]
+ impl HelperImpl of HelperTrait {
+ // toggle whether or not receiver says it supports the interface id
+ #[external(v0)]
+ fn set_supports(ref self: ContractState, support: bool) {
+ self._supports.write(support);
+ }
+
+ #[external(v0)]
+ fn supports_interface(self: @ContractState, interface_id: u32) -> bool {
+ self._supports.read()
+ }
+ }
+}
diff --git a/contracts/src/token/mock/valid_erc667_receiver.cairo b/contracts/src/token/mock/valid_erc667_receiver.cairo
new file mode 100644
index 0000000..c492cd7
--- /dev/null
+++ b/contracts/src/token/mock/valid_erc667_receiver.cairo
@@ -0,0 +1,41 @@
+use starknet::ContractAddress;
+#[starknet::interface]
+trait MockValidReceiver {
+ fn verify(self: @TContractState) -> ContractAddress;
+}
+
+#[starknet::contract]
+mod ValidReceiver {
+ use starknet::ContractAddress;
+ use array::ArrayTrait;
+ use plugin::libraries::token::erc677::IERC677Receiver;
+
+ #[storage]
+ struct Storage {
+ _sender: ContractAddress,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState) {}
+
+
+ #[abi(embed_v0)]
+ impl ERC677Receiver of IERC677Receiver {
+ fn on_token_transfer(
+ ref self: ContractState, sender: ContractAddress, value: u256, data: Array
+ ) {
+ self._sender.write(sender);
+ }
+
+ fn supports_interface(ref self: ContractState, interface_id: u32) -> bool {
+ true
+ }
+ }
+
+ #[abi(embed_v0)]
+ impl ValidReceiver of super::MockValidReceiver {
+ fn verify(self: @ContractState) -> ContractAddress {
+ self._sender.read()
+ }
+ }
+}
diff --git a/contracts/src/utils.cairo b/contracts/src/utils.cairo
new file mode 100644
index 0000000..13db189
--- /dev/null
+++ b/contracts/src/utils.cairo
@@ -0,0 +1,10 @@
+use integer::U128IntoFelt252;
+use integer::u128s_from_felt252;
+use integer::U128sFromFelt252Result;
+fn split_felt(felt: felt252) -> (u128, u128) {
+ match u128s_from_felt252(felt) {
+ U128sFromFelt252Result::Narrow(low) => (0_u128, low),
+ U128sFromFelt252Result::Wide((high, low)) => (high, low),
+ }
+}
+
diff --git a/contracts/test/access/behavior/ownable.ts b/contracts/test/access/behavior/ownable.ts
deleted file mode 100644
index 0c7d16c..0000000
--- a/contracts/test/access/behavior/ownable.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { expect } from 'chai'
-import { starknet } from 'hardhat'
-import { StarknetContract, Account } from 'hardhat/types/runtime'
-
-export type BeforeFn = () => Promise
-export type TestData = {
- ownable: StarknetContract
- alice: Account
- bob: Account
-}
-
-// NOTICE: Leading zeros are trimmed for an encoded felt (number).
-// To decode, the raw felt needs to be start padded up to max felt size (252 bits or < 32 bytes).
-const hexPadStart = (data: number | bigint, len: number) => {
- return `0x${data.toString(16).padStart(len, '0')}`
-}
-
-const ADDRESS_LEN = 32 * 2 // 32 bytes (hex)
-
-const addresses = (t: TestData) => ({
- bob: t.bob.starknetContract.address,
- alice: t.alice.starknetContract.address,
-})
-
-const expectOwner = async (c: StarknetContract, expected: string) => {
- const { owner: raw } = await c.call('owner')
-
- const owner = hexPadStart(raw, ADDRESS_LEN)
- expect(owner).to.deep.equal(expected)
-}
-
-const expectProposedOwner = async (c: StarknetContract, expected: string) => {
- const { proposed_owner: raw } = await c.call('proposed_owner')
-
- const proposedOwner = hexPadStart(raw, ADDRESS_LEN)
- expect(proposedOwner).to.deep.equal(expected)
-}
-
-// idempotent - end with original owner
-export const shouldBehaveLikeOwnableContract = (beforeFn: BeforeFn) => {
- describe('ownable behavior', function () {
- let t: TestData
-
- before(async () => {
- t = await beforeFn()
- })
-
- // TODO: test 'owner', 'proposed_owner', 'transfer_ownership', 'accept_ownership' in depth
-
- it(`should have 'owner' set`, async () => {
- const { alice } = addresses(t)
-
- // initial owner is alice
- await expectOwner(t.ownable, alice)
- })
-
- it(`should be able to 'transfer_ownership'`, async () => {
- const { alice, bob } = addresses(t)
-
- await t.alice.invoke(t.ownable, 'transfer_ownership', {
- new_owner: bob,
- })
-
- // owner is still alice
- await expectOwner(t.ownable, alice)
- await expectProposedOwner(t.ownable, bob)
- })
-
- it(`should be able to 'accept_ownership'`, async () => {
- const { bob } = addresses(t)
-
- await t.bob.invoke(t.ownable, 'accept_ownership')
-
- // owner is now bob
- await expectOwner(t.ownable, bob)
- await expectProposedOwner(t.ownable, hexPadStart(0, ADDRESS_LEN)) // 0x0
- })
-
- it(`should be able to 'transfer_ownership' back`, async () => {
- const { alice, bob } = addresses(t)
-
- await t.bob.invoke(t.ownable, 'transfer_ownership', {
- new_owner: alice,
- })
-
- // owner is still bob
- await expectOwner(t.ownable, bob)
- await expectProposedOwner(t.ownable, alice)
- })
-
- it(`should be able to 'accept_ownership' again`, async () => {
- const { alice } = addresses(t)
-
- await t.alice.invoke(t.ownable, 'accept_ownership')
-
- // owner is now alice
- await expectOwner(t.ownable, alice)
- await expectProposedOwner(t.ownable, hexPadStart(0, ADDRESS_LEN)) // 0x0
- })
-
- it(`should fail with account without fees`, async () => {
- const accountNoFees = await starknet.OpenZeppelinAccount.createAccount()
-
- await t.alice.invoke(t.ownable, 'transfer_ownership', {
- new_owner: accountNoFees.address,
- })
-
- try {
- await accountNoFees.invoke(t.ownable, 'accept_ownership', { maxFee: 1e18 })
- expect.fail()
- } catch (err: any) {}
- })
- })
-}
diff --git a/packages-ts/starknet/src/account.ts b/contracts/test/account.ts
similarity index 91%
rename from packages-ts/starknet/src/account.ts
rename to contracts/test/account.ts
index e0d34c4..c5b240e 100644
--- a/packages-ts/starknet/src/account.ts
+++ b/contracts/test/account.ts
@@ -1,4 +1,4 @@
-import { Account, SequencerProvider, ec, uint256 } from 'starknet'
+import { Account, RpcProvider, ec, uint256, constants } from 'starknet'
export const ERC20_ADDRESS = '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7'
@@ -24,7 +24,7 @@ interface FunderOptions {
network?: string
gateway?: string
accountAddr?: string
- keyPair?: Uint8Array
+ keyPair: Uint8Array
}
// Define the Strategy to use depending on the network.
@@ -71,9 +71,9 @@ class DevnetFundingStrategy implements IFundingStrategy {
// Fund the Account on Testnet
class AllowanceFundingStrategy implements IFundingStrategy {
- public async fund(accounts: FundAccounts[], opts: FunderOptions) {
- const provider = new SequencerProvider({
- baseUrl: 'https://alpha4.starknet.io',
+ public async fund(accounts: FundAccounts[], opts: Required) {
+ const provider = new RpcProvider({
+ nodeUrl: constants.NetworkName.SN_SEPOLIA,
})
const operator = new Account(provider, opts.accountAddr, opts.keyPair)
diff --git a/contracts/test/constants.ts b/contracts/test/constants.ts
index ea0bd93..e7ff055 100644
--- a/contracts/test/constants.ts
+++ b/contracts/test/constants.ts
@@ -1,2 +1,5 @@
/** 15 min */
export const TIMEOUT = 900_000
+
+export const STARKNET_DEVNET_URL = 'http://127.0.0.1:5050'
+export const ETH_DEVNET_URL = 'http://127.0.0.1:8545'
diff --git a/contracts/test/emergency/StarknetValidator.test.ts b/contracts/test/emergency/StarknetValidator.test.ts
index c33ce9f..9cf34b3 100644
--- a/contracts/test/emergency/StarknetValidator.test.ts
+++ b/contracts/test/emergency/StarknetValidator.test.ts
@@ -1,23 +1,19 @@
-import { ethers, starknet, network } from 'hardhat'
-import { Contract, ContractFactory } from 'ethers'
-import { hash } from 'starknet'
-import {
- Account,
- StarknetContractFactory,
- StarknetContract,
- HttpNetworkConfig,
-} from 'hardhat/types'
-import { expect } from 'chai'
-import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
-import { abi as aggregatorAbi } from '../../artifacts/@pluginv3.0/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol/AggregatorV3Interface.json'
-import { abi as accessControllerAbi } from '../../artifacts/@pluginv3.0/contracts/src/v0.8/interfaces/AccessControllerInterface.sol/AccessControllerInterface.json'
-import { abi as starknetMessagingAbi } from '../../artifacts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessaging.sol/IStarknetMessaging.json'
+import { abi as starknetMessagingAbi } from '../../artifacts/vendor/starkware-libs/cairo-lang/src/starkware/starknet/solidity/IStarknetMessaging.sol/IStarknetMessaging.json'
+import { abi as accessControllerAbi } from '../../artifacts/@plugin/contracts/src/v0.8/interfaces/AccessControllerInterface.sol/AccessControllerInterface.json'
+import { abi as aggregatorAbi } from '../../artifacts/@plugin/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol/AggregatorV3Interface.json'
+import { fetchStarknetAccount, getStarknetContractArtifacts, waitForTransactions } from '../utils'
+import { Contract as StarknetContract, RpcProvider, CallData, Account, hash } from 'starknet'
import { deployMockContract, MockContract } from '@ethereum-waffle/mock-contract'
-import { account, addCompilationToNetwork } from '@pluginv3.0/starknet'
+import { BigNumber, Contract as EthersContract, ContractFactory } from 'ethers'
+import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
+import * as l1l2messaging from '../l1-l2-messaging'
+import { STARKNET_DEVNET_URL } from '../constants'
+import * as account from '../account'
+import { ethers } from 'hardhat'
+import { expect } from 'chai'
describe('StarknetValidator', () => {
- /** Fake L2 target */
- const networkUrl: string = (network.config as HttpNetworkConfig).url
+ const provider = new RpcProvider({ nodeUrl: STARKNET_DEVNET_URL })
const opts = account.makeFunderOptsFromEnv()
const funder = new account.Funder(opts)
@@ -27,27 +23,32 @@ describe('StarknetValidator', () => {
let alice: SignerWithAddress
let starknetValidatorFactory: ContractFactory
- let starknetValidator: Contract
+ let starknetValidator: EthersContract
let mockStarknetMessagingFactory: ContractFactory
- let mockStarknetMessaging: Contract
+ let mockStarknetMessaging: EthersContract
let mockGasPriceFeed: MockContract
let mockAccessController: MockContract
let mockAggregator: MockContract
- let l2ContractFactory: StarknetContractFactory
let l2Contract: StarknetContract
before(async () => {
- await addCompilationToNetwork(
- 'src/plugin/solidity/emergency/StarknetValidator.sol:StarknetValidator',
- )
+ // Setup L2 account
+ defaultAccount = await fetchStarknetAccount()
+ await funder.fund([{ account: defaultAccount.address, amount: 1e21 }])
- // Deploy L2 account
- defaultAccount = await starknet.OpenZeppelinAccount.createAccount()
+ // Deploy L2 feed contract
+ const ddL2Contract = await defaultAccount.declareAndDeploy({
+ ...getStarknetContractArtifacts('SequencerUptimeFeed'),
+ constructorCalldata: CallData.compile({
+ initial_status: 0,
+ owner_address: defaultAccount.address,
+ }),
+ })
- // Fund L2 account
- await funder.fund([{ account: defaultAccount.address, amount: 1e21 }])
- await defaultAccount.deployAccount()
+ // Creates a starknet contract instance for the l2 feed
+ const { abi: l2FeedAbi } = await provider.getClassByHash(ddL2Contract.declare.class_hash)
+ l2Contract = new StarknetContract(l2FeedAbi, ddL2Contract.deploy.address, provider)
// Fetch predefined L1 EOA accounts
const accounts = await ethers.getSigners()
@@ -55,24 +56,6 @@ describe('StarknetValidator', () => {
eoaValidator = accounts[1]
alice = accounts[2]
- // Deploy L2 feed contract
- l2ContractFactory = await starknet.getContractFactory('sequencer_uptime_feed')
- await defaultAccount.declare(l2ContractFactory)
-
- l2Contract = await defaultAccount.deploy(l2ContractFactory, {
- initial_status: 0,
- owner_address: defaultAccount.starknetContract.address,
- })
-
- // Deploy the MockStarknetMessaging contract used to simulate L1 - L2 comms
- mockStarknetMessagingFactory = await ethers.getContractFactory(
- 'MockStarknetMessaging',
- deployer,
- )
- const messageCancellationDelay = 5 * 60 // seconds
- mockStarknetMessaging = await mockStarknetMessagingFactory.deploy(messageCancellationDelay)
- await mockStarknetMessaging.deployed()
-
// Deploy the mock feed
mockGasPriceFeed = await deployMockContract(deployer, aggregatorAbi)
await mockGasPriceFeed.mock.latestRoundData.returns(
@@ -98,6 +81,15 @@ describe('StarknetValidator', () => {
})
beforeEach(async () => {
+ // Deploy the MockStarknetMessaging contract used to simulate L1 - L2 comms
+ mockStarknetMessagingFactory = await ethers.getContractFactory(
+ 'MockStarknetMessaging',
+ deployer,
+ )
+ const messageCancellationDelay = 5 * 60 // seconds
+ mockStarknetMessaging = await mockStarknetMessagingFactory.deploy(messageCancellationDelay)
+ await mockStarknetMessaging.deployed()
+
// Deploy the L1 StarknetValidator
starknetValidatorFactory = await ethers.getContractFactory('StarknetValidator', deployer)
starknetValidator = await starknetValidatorFactory.deploy(
@@ -107,10 +99,15 @@ describe('StarknetValidator', () => {
mockAggregator.address,
l2Contract.address,
0,
+ 0,
)
// Point the L2 feed contract to receive from the L1 StarknetValidator contract
- await defaultAccount.invoke(l2Contract, 'set_l1_sender', { address: starknetValidator.address })
+ await defaultAccount.execute(
+ l2Contract.populate('set_l1_sender', {
+ address: starknetValidator.address,
+ }),
+ )
})
describe('#constructor', () => {
@@ -123,6 +120,7 @@ describe('StarknetValidator', () => {
mockAggregator.address,
l2Contract.address,
0,
+ 0,
),
).to.be.revertedWithCustomError(starknetValidator, 'InvalidStarknetMessagingAddress')
})
@@ -136,6 +134,7 @@ describe('StarknetValidator', () => {
mockAggregator.address,
0,
0,
+ 0,
),
).to.be.revertedWithCustomError(starknetValidator, 'InvalidL2FeedAddress')
})
@@ -149,10 +148,25 @@ describe('StarknetValidator', () => {
ethers.constants.AddressZero,
l2Contract.address,
0,
+ 0,
),
).to.be.revertedWithCustomError(starknetValidator, 'InvalidSourceAggregatorAddress')
})
+ it('reverts when the Access Controller address is zero', async () => {
+ await expect(
+ starknetValidatorFactory.deploy(
+ mockStarknetMessaging.address,
+ ethers.constants.AddressZero,
+ mockGasPriceFeed.address,
+ mockAggregator.address,
+ l2Contract.address,
+ 0,
+ 0,
+ ),
+ ).to.be.revertedWithCustomError(starknetValidator, 'InvalidAccessControllerAddress')
+ })
+
it('reverts when the L1 Gas Price feed address is zero', async () => {
await expect(
starknetValidatorFactory.deploy(
@@ -162,6 +176,7 @@ describe('StarknetValidator', () => {
mockAggregator.address,
l2Contract.address,
0,
+ 0,
),
).to.be.revertedWithCustomError(starknetValidator, 'InvalidGasPriceL1FeedAddress')
})
@@ -170,6 +185,7 @@ describe('StarknetValidator', () => {
const gasConfig = await starknetValidator.getGasConfig()
expect(gasConfig.gasEstimate).to.equal(0) // Initialized with 0 in before function
expect(gasConfig.gasPriceL1Feed).to.hexEqual(mockGasPriceFeed.address)
+ expect(gasConfig.gasAdjustment).to.equal(0)
})
it('is initialized with the correct access controller address', async () => {
@@ -228,6 +244,7 @@ describe('StarknetValidator', () => {
mockAggregator.address,
l2Contract.address,
0,
+ 0,
)
await starknetValidator.addAccess(deployer.address)
@@ -240,9 +257,10 @@ describe('StarknetValidator', () => {
describe('#setConfigAC', () => {
describe('when called by non owner', () => {
it('reverts', async () => {
- await expect(
- starknetValidator.connect(alice).setConfigAC(ethers.constants.AddressZero),
- ).to.be.revertedWith('Only callable by owner')
+ const newACAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
+ await expect(starknetValidator.connect(alice).setConfigAC(newACAddr)).to.be.revertedWith(
+ 'Only callable by owner',
+ )
})
})
@@ -266,6 +284,12 @@ describe('StarknetValidator', () => {
expect(receipt.events).is.empty
expect(await starknetValidator.getConfigAC()).to.equal(mockAccessController.address)
})
+
+ it('reverts if address is zero', async () => {
+ await expect(
+ starknetValidator.connect(deployer).setConfigAC(ethers.constants.AddressZero),
+ ).to.be.revertedWithCustomError(starknetValidator, 'InvalidAccessControllerAddress')
+ })
})
})
@@ -318,7 +342,7 @@ describe('StarknetValidator', () => {
it('reverts', async () => {
await expect(
- starknetValidator.connect(alice).setGasConfig(0, mockGasPriceFeed.address),
+ starknetValidator.connect(alice).setGasConfig(0, mockGasPriceFeed.address, 0),
).to.be.revertedWithCustomError(starknetValidator, 'AccessForbidden')
})
})
@@ -327,112 +351,108 @@ describe('StarknetValidator', () => {
it('correctly sets the gas config', async () => {
const newGasEstimate = 25000
const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await starknetValidator.connect(deployer).setGasConfig(newGasEstimate, newFeedAddr)
+ // gasAdjustment of 110 equates to 1.1x
+ const newGasAdjustment = 110
+ await starknetValidator
+ .connect(deployer)
+ .setGasConfig(newGasEstimate, newFeedAddr, newGasAdjustment)
const gasConfig = await starknetValidator.getGasConfig()
expect(gasConfig.gasEstimate).to.equal(newGasEstimate)
expect(gasConfig.gasPriceL1Feed).to.hexEqual(newFeedAddr)
+ expect(gasConfig.gasAdjustment).to.equal(newGasAdjustment)
})
it('emits an event', async () => {
const newGasEstimate = 25000
const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await expect(starknetValidator.connect(deployer).setGasConfig(newGasEstimate, newFeedAddr))
+ const newGasAdjustment = 110
+ await expect(
+ starknetValidator
+ .connect(deployer)
+ .setGasConfig(newGasEstimate, newFeedAddr, newGasAdjustment),
+ )
.to.emit(starknetValidator, 'GasConfigSet')
- .withArgs(newGasEstimate, newFeedAddr)
+ .withArgs(newGasEstimate, newFeedAddr, newGasAdjustment)
})
describe('when l1 gas price feed address is the zero address', () => {
it('reverts', async () => {
await expect(
- starknetValidator.connect(deployer).setGasConfig(25000, ethers.constants.AddressZero),
+ starknetValidator
+ .connect(deployer)
+ .setGasConfig(25000, ethers.constants.AddressZero, 0),
).to.be.revertedWithCustomError(starknetValidator, 'InvalidGasPriceL1FeedAddress')
})
})
})
- describe('when access controller address is set', () => {
- describe('when called by an address with access', () => {
- beforeEach(async () => {
- await mockAccessController.mock.hasAccess.returns(true)
- })
+ describe('when called by an address with access', () => {
+ beforeEach(async () => {
+ await mockAccessController.mock.hasAccess.returns(true)
+ })
- it('correctly sets the gas config', async () => {
- const newGasEstimate = 25000
- const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await starknetValidator.connect(eoaValidator).setGasConfig(newGasEstimate, newFeedAddr)
- const gasConfig = await starknetValidator.getGasConfig()
- expect(gasConfig.gasEstimate).to.equal(newGasEstimate)
- expect(gasConfig.gasPriceL1Feed).to.hexEqual(newFeedAddr)
- })
+ it('correctly sets the gas config', async () => {
+ const newGasEstimate = 25000
+ const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
+ const newGasAdjustment = 110
+ await starknetValidator
+ .connect(eoaValidator)
+ .setGasConfig(newGasEstimate, newFeedAddr, newGasAdjustment)
+ const gasConfig = await starknetValidator.getGasConfig()
+ expect(gasConfig.gasEstimate).to.equal(newGasEstimate)
+ expect(gasConfig.gasPriceL1Feed).to.hexEqual(newFeedAddr)
+ expect(gasConfig.gasAdjustment).to.equal(newGasAdjustment)
+ })
- it('emits an event', async () => {
- const newGasEstimate = 25000
- const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await expect(
- starknetValidator.connect(eoaValidator).setGasConfig(newGasEstimate, newFeedAddr),
- )
- .to.emit(starknetValidator, 'GasConfigSet')
- .withArgs(newGasEstimate, newFeedAddr)
- })
+ it('emits an event', async () => {
+ const newGasEstimate = 25000
+ const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
+ const newGasAdjustment = 110
+ await expect(
+ starknetValidator
+ .connect(eoaValidator)
+ .setGasConfig(newGasEstimate, newFeedAddr, newGasAdjustment),
+ )
+ .to.emit(starknetValidator, 'GasConfigSet')
+ .withArgs(newGasEstimate, newFeedAddr, newGasAdjustment)
+ })
- describe('when l1 gas price feed address is the zero address', () => {
- it('reverts', async () => {
- await expect(
- starknetValidator
- .connect(eoaValidator)
- .setGasConfig(25000, ethers.constants.AddressZero),
- ).to.be.revertedWithCustomError(starknetValidator, 'InvalidGasPriceL1FeedAddress')
- })
+ describe('when l1 gas price feed address is the zero address', () => {
+ it('reverts', async () => {
+ await expect(
+ starknetValidator
+ .connect(eoaValidator)
+ .setGasConfig(25000, ethers.constants.AddressZero, 0),
+ ).to.be.revertedWithCustomError(starknetValidator, 'InvalidGasPriceL1FeedAddress')
})
})
})
+ })
- describe('when access controller address is not set', () => {
- beforeEach(async () => {
- await starknetValidator.connect(deployer).setConfigAC(ethers.constants.AddressZero)
- })
-
- describe('when called by an address without access', () => {
- beforeEach(async () => {
- await mockAccessController.mock.hasAccess.returns(false)
- })
+ describe('#approximateGasPrice', () => {
+ it('calculates gas price with scalar coefficient', async () => {
+ await mockGasPriceFeed.mock.latestRoundData.returns(
+ '0' /** roundId */,
+ 96800000000 /** answer */,
+ '0' /** startedAt */,
+ '0' /** updatedAt */,
+ '0' /** answeredInRound */,
+ )
+ // 96800000000 is the mocked value from gas feed
+ const expectedGasPrice = BigNumber.from(96800000000).mul(110).div(100)
- it('correctly sets the gas config', async () => {
- const newGasEstimate = 25000
- const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await starknetValidator.connect(eoaValidator).setGasConfig(newGasEstimate, newFeedAddr)
- const gasConfig = await starknetValidator.getGasConfig()
- expect(gasConfig.gasEstimate).to.equal(newGasEstimate)
- expect(gasConfig.gasPriceL1Feed).to.hexEqual(newFeedAddr)
- })
+ await starknetValidator.connect(deployer).setGasConfig(0, mockGasPriceFeed.address, 110)
- it('emits an event', async () => {
- const newGasEstimate = 25000
- const newFeedAddr = '0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4'
- await expect(
- starknetValidator.connect(eoaValidator).setGasConfig(newGasEstimate, newFeedAddr),
- )
- .to.emit(starknetValidator, 'GasConfigSet')
- .withArgs(newGasEstimate, newFeedAddr)
- })
+ const gasPrice = await starknetValidator.connect(deployer).approximateGasPrice()
- describe('when l1 gas price feed address is the zero address', () => {
- it('reverts', async () => {
- await expect(
- starknetValidator
- .connect(eoaValidator)
- .setGasConfig(25000, ethers.constants.AddressZero),
- ).to.be.revertedWithCustomError(starknetValidator, 'InvalidGasPriceL1FeedAddress')
- })
- })
- })
+ expect(gasPrice).to.equal(expectedGasPrice)
})
})
describe('#validate', () => {
beforeEach(async () => {
await expect(
- deployer.sendTransaction({ to: starknetValidator.address, value: 100n })
+ deployer.sendTransaction({ to: starknetValidator.address, value: 100n }),
).to.changeEtherBalance(starknetValidator, 100n)
})
@@ -442,28 +462,27 @@ describe('StarknetValidator', () => {
})
it('should not revert if `sequencer_uptime_feed.latest_round_data` called by an Account with no explicit access (Accounts are allowed read access)', async () => {
- const { round } = await l2Contract.call('latest_round_data')
- expect(round.answer).to.equal(0n)
+ const result = await l2Contract.latest_round_data()
+ expect(result['answer']).to.equal('0')
})
it('should deploy the messaging contract', async () => {
- const { address, l1_provider } = await starknet.devnet.loadL1MessagingContract(networkUrl)
- expect(address).not.to.be.undefined
- expect(l1_provider).to.equal(networkUrl)
+ const { messaging_contract_address } = await l1l2messaging.loadL1MessagingContract({
+ address: mockStarknetMessaging.address,
+ })
+ expect(messaging_contract_address).not.to.be.undefined
})
it('should load the already deployed contract if the address is provided', async () => {
- const { address: loadedFrom } = await starknet.devnet.loadL1MessagingContract(
- networkUrl,
- mockStarknetMessaging.address,
- )
-
- expect(mockStarknetMessaging.address).to.hexEqual(loadedFrom)
+ const { messaging_contract_address } = await l1l2messaging.loadL1MessagingContract({
+ address: mockStarknetMessaging.address,
+ })
+ expect(mockStarknetMessaging.address).to.hexEqual(messaging_contract_address)
})
it('should send a message to the L2 contract', async () => {
// Load the mock messaging contract
- await starknet.devnet.loadL1MessagingContract(networkUrl, mockStarknetMessaging.address)
+ await l1l2messaging.loadL1MessagingContract({ address: mockStarknetMessaging.address })
// Return gas price of 1
await mockGasPriceFeed.mock.latestRoundData.returns(
@@ -474,35 +493,53 @@ describe('StarknetValidator', () => {
'0' /** answeredInRound */,
)
-
-
// Simulate L1 transmit + validate
- await starknetValidator.addAccess(eoaValidator.address)
- // by default the gas config is 0, we need to change it or we will submit a 0 fee
const newGasEstimate = 1
- await starknetValidator
- .connect(deployer)
- .setGasConfig(newGasEstimate, mockGasPriceFeed.address)
- await starknetValidator.connect(eoaValidator).validate(0, 0, 1, 1) // gasPrice (1) * newGasEstimate (1)
+ const receipts = await waitForTransactions([
+ // Add access
+ () => starknetValidator.addAccess(eoaValidator.address),
+
+ // By default the gas config is 0, we need to change it or we will submit a 0 fee
+ () =>
+ starknetValidator
+ .connect(deployer)
+ .setGasConfig(newGasEstimate, mockGasPriceFeed.address, 100),
+
+ // gasPrice (1) * newGasEstimate (1)
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 1),
+ ])
// Simulate the L1 - L2 comms
- const resp = await starknet.devnet.flush()
- const msgFromL1 = resp.consumed_messages.from_l1
+ const resp = await l1l2messaging.flush()
+ const msgFromL1 = resp.messages_to_l2
expect(msgFromL1).to.have.a.lengthOf(1)
- expect(resp.consumed_messages.from_l2).to.be.empty
+ expect(resp.messages_to_l1).to.be.empty
- expect(msgFromL1[0].args.from_address).to.hexEqual(starknetValidator.address)
- expect(msgFromL1[0].args.to_address).to.hexEqual(l2Contract.address)
- expect(msgFromL1[0].address).to.hexEqual(mockStarknetMessaging.address)
+ expect(msgFromL1.at(0)?.l1_contract_address).to.hexEqual(starknetValidator.address)
+ expect(msgFromL1.at(0)?.l2_contract_address).to.hexEqual(l2Contract.address)
// Assert L2 effects
- const res = await l2Contract.call('latest_round_data')
- expect(res.round.answer).to.equal(1n)
+ const result = await l2Contract.latest_round_data()
+
+ // Logging (to help debug potential flaky test)
+ console.log(
+ JSON.stringify(
+ {
+ latestRoundData: result,
+ flushResponse: resp,
+ txReceipts: receipts,
+ },
+ (_, value) => (typeof value === 'bigint' ? value.toString() : value),
+ 2,
+ ),
+ )
+
+ expect(result['answer']).to.equal('1')
})
it('should always send a **boolean** message to L2 contract', async () => {
// Load the mock messaging contract
- await starknet.devnet.loadL1MessagingContract(networkUrl, mockStarknetMessaging.address)
+ await l1l2messaging.loadL1MessagingContract({ address: mockStarknetMessaging.address })
// Return gas price of 1
await mockGasPriceFeed.mock.latestRoundData.returns(
@@ -514,32 +551,52 @@ describe('StarknetValidator', () => {
)
// Simulate L1 transmit + validate
- await starknetValidator.addAccess(eoaValidator.address)
- // by default the gas config is 0, we need to change it or we will submit a 0 fee
const newGasEstimate = 1
- await starknetValidator
- .connect(deployer)
- .setGasConfig(newGasEstimate, mockGasPriceFeed.address)
- await starknetValidator.connect(eoaValidator).validate(0, 0, 1, 127) // incorrect value
+ const receipts = await waitForTransactions([
+ // Add access
+ () => starknetValidator.connect(deployer).addAccess(eoaValidator.address),
+
+ // By default the gas config is 0, we need to change it or we will submit a 0 fee
+ () =>
+ starknetValidator
+ .connect(deployer)
+ .setGasConfig(newGasEstimate, mockGasPriceFeed.address, 100),
+
+ // Incorrect value
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 127),
+ ])
// Simulate the L1 - L2 comms
- const resp = await starknet.devnet.flush()
- const msgFromL1 = resp.consumed_messages.from_l1
+ const resp = await l1l2messaging.flush()
+ const msgFromL1 = resp.messages_to_l2
expect(msgFromL1).to.have.a.lengthOf(1)
- expect(resp.consumed_messages.from_l2).to.be.empty
+ expect(resp.messages_to_l1).to.be.empty
- expect(msgFromL1[0].args.from_address).to.hexEqual(starknetValidator.address)
- expect(msgFromL1[0].args.to_address).to.hexEqual(l2Contract.address)
- expect(msgFromL1[0].address).to.hexEqual(mockStarknetMessaging.address)
+ expect(msgFromL1[0].l1_contract_address).to.hexEqual(starknetValidator.address)
+ expect(msgFromL1[0].l2_contract_address).to.hexEqual(l2Contract.address)
// Assert L2 effects
- const res = await l2Contract.call('latest_round_data')
- expect(res.round.answer).to.equal(0n) // status unchanged - incorrect value treated as false
+ const result = await l2Contract.latest_round_data()
+
+ // Logging (to help debug potential flaky test)
+ console.log(
+ JSON.stringify(
+ {
+ latestRoundData: result,
+ flushResponse: resp,
+ txReceipts: receipts,
+ },
+ (_, value) => (typeof value === 'bigint' ? value.toString() : value),
+ 2,
+ ),
+ )
+
+ expect(result['answer']).to.equal('0') // status unchanged - incorrect value treated as false
})
it('should send multiple messages', async () => {
// Load the mock messaging contract
- await starknet.devnet.loadL1MessagingContract(networkUrl, mockStarknetMessaging.address)
+ await l1l2messaging.loadL1MessagingContract({ address: mockStarknetMessaging.address })
// Return gas price of 1
await mockGasPriceFeed.mock.latestRoundData.returns(
@@ -551,38 +608,68 @@ describe('StarknetValidator', () => {
)
// Simulate L1 transmit + validate
- await starknetValidator.addAccess(eoaValidator.address)
- const c = starknetValidator.connect(eoaValidator)
- // by default the gas config is 0, we need to change it or we will submit a 0 fee
+ const messages = new Array()
const newGasEstimate = 1
- await starknetValidator
- .connect(deployer)
- .setGasConfig(newGasEstimate, mockGasPriceFeed.address)
- await c.validate(0, 0, 1, 1)
- await c.validate(0, 0, 1, 1)
- await c.validate(0, 0, 1, 127) // incorrect value
- await c.validate(0, 0, 1, 0) // final status
-
- // Simulate the L1 - L2 comms
- const resp = await starknet.devnet.flush()
- const msgFromL1 = resp.consumed_messages.from_l1
- expect(msgFromL1).to.have.a.lengthOf(4)
- expect(resp.consumed_messages.from_l2).to.be.empty
+ const receipts = await waitForTransactions(
+ [
+ // Add access
+ () => starknetValidator.connect(deployer).addAccess(eoaValidator.address),
+
+ // By default the gas config is 0, we need to change it or we will submit a 0 fee
+ () =>
+ starknetValidator
+ .connect(deployer)
+ .setGasConfig(newGasEstimate, mockGasPriceFeed.address, 100),
+
+ // Validate
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 1),
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 1),
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 127), // incorrect value
+ () => starknetValidator.connect(eoaValidator).validate(0, 0, 1, 0), // final status
+ ],
+ async () => {
+ // Simulate the L1 - L2 comms
+ const resp = await l1l2messaging.flush()
+ if (resp.messages_to_l2.length !== 0) {
+ expect(resp.messages_to_l1).to.be.empty
+
+ const msgFromL1 = resp.messages_to_l2
+ expect(msgFromL1).to.have.a.lengthOf(1)
+ expect(msgFromL1[0].l1_contract_address).to.hexEqual(starknetValidator.address)
+ expect(msgFromL1[0].l2_contract_address).to.hexEqual(l2Contract.address)
+
+ messages.push(resp)
+ }
+ },
+ )
- expect(msgFromL1[0].args.from_address).to.hexEqual(starknetValidator.address)
- expect(msgFromL1[0].args.to_address).to.hexEqual(l2Contract.address)
- expect(msgFromL1[0].address).to.hexEqual(mockStarknetMessaging.address)
+ // Makes sure the correct number of messages were transmitted
+ expect(messages.length).to.eq(4)
// Assert L2 effects
- const res = await l2Contract.call('latest_round_data')
- expect(res.round.answer).to.equal(0n) // final status 0
+ const result = await l2Contract.latest_round_data()
+
+ // Logging (to help debug potential flaky test)
+ console.log(
+ JSON.stringify(
+ {
+ latestRoundData: result,
+ flushResponse: messages,
+ txReceipts: receipts,
+ },
+ (_, value) => (typeof value === 'bigint' ? value.toString() : value),
+ 2,
+ ),
+ )
+
+ expect(result['answer']).to.equal('0') // final status 0
})
})
describe('#withdrawFunds', () => {
beforeEach(async () => {
await expect(() =>
- deployer.sendTransaction({ to: starknetValidator.address, value: 10 })
+ deployer.sendTransaction({ to: starknetValidator.address, value: 10 }),
).to.changeEtherBalance(starknetValidator, 10n)
})
@@ -612,7 +699,7 @@ describe('StarknetValidator', () => {
describe('#withdrawFundsTo', () => {
beforeEach(async () => {
await expect(() =>
- deployer.sendTransaction({ to: starknetValidator.address, value: 10 })
+ deployer.sendTransaction({ to: starknetValidator.address, value: 10 }),
).to.changeEtherBalance(starknetValidator, 10)
})
diff --git a/contracts/test/emergency/sequencer_uptime_feed.test.ts b/contracts/test/emergency/sequencer_uptime_feed.test.ts
deleted file mode 100644
index 60ab169..0000000
--- a/contracts/test/emergency/sequencer_uptime_feed.test.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import { expect } from 'chai'
-import { starknet } from 'hardhat'
-import { StarknetContract, Account } from 'hardhat/types/runtime'
-import { num } from 'starknet'
-import { shouldBehaveLikeOwnableContract } from '../access/behavior/ownable'
-import { account, expectInvokeError } from '@pluginv3.0/starknet'
-
-describe('SequencerUptimeFeed', function () {
- this.timeout(300_000)
-
- let owner: Account
- let nonOwner: Account
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
- // should be beforeeach, but that'd be horribly slow. Just remember that the tests are not idempotent
- before(async function () {
- owner = await starknet.OpenZeppelinAccount.createAccount()
- nonOwner = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([
- { account: owner.address, amount: 1e21 },
- { account: nonOwner.address, amount: 1e21 },
- ])
- await owner.deployAccount()
- await nonOwner.deployAccount()
- })
-
- shouldBehaveLikeOwnableContract(async () => {
- const alice = owner
- const bob = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: bob.address, amount: 1e21 }])
-
- await bob.deployAccount()
-
- const feedFactory = await starknet.getContractFactory('sequencer_uptime_feed')
- await alice.declare(feedFactory)
-
- const feed = await alice.deploy(feedFactory, {
- initial_status: 0,
- owner_address: num.toBigInt(alice.starknetContract.address),
- })
-
- return { ownable: feed, alice, bob }
- })
-
- describe('Test access control via inherited `SimpleReadAccessController`', function () {
- const user = 101
- let uptimeFeedContract: StarknetContract
-
- before(async function () {
- const uptimeFeedFactory = await starknet.getContractFactory('sequencer_uptime_feed')
- await owner.declare(uptimeFeedFactory)
-
- uptimeFeedContract = await owner.deploy(uptimeFeedFactory, {
- initial_status: 0,
- owner_address: num.toBigInt(owner.starknetContract.address),
- })
- })
-
- it('should block non-owners from making admin changes', async function () {
- await owner.invoke(uptimeFeedContract, 'add_access', { user })
-
- await expectInvokeError(
- nonOwner.invoke(uptimeFeedContract, 'add_access', { user }),
- 'Ownable: caller is not the owner',
- )
- })
-
- it('should report access information correctly', async function () {
- {
- const res = await uptimeFeedContract.call('has_access', { user: user, data: [] })
- expect(res.bool).to.equal(1n)
- }
-
- {
- const res = await uptimeFeedContract.call('has_access', { user: user + 1, data: [] })
- expect(res.bool).to.equal(0n)
- }
- })
-
- it('should error on `check_access` without access', async function () {
- await uptimeFeedContract.call('check_access', { user: user })
-
- await expectInvokeError(
- owner.invoke(uptimeFeedContract, 'check_access', { user: user + 1 }),
- 'SimpleReadAccessController: address does not have access',
- )
- })
-
- it('should disable access check', async function () {
- await owner.invoke(uptimeFeedContract, 'disable_access_check', {})
-
- const res = await uptimeFeedContract.call('has_access', { user: user + 1, data: [] })
- expect(res.bool).to.equal(1n)
- })
-
- it('should enable access check', async function () {
- await owner.invoke(uptimeFeedContract, 'enable_access_check', {})
-
- const res = await uptimeFeedContract.call('has_access', { user: user + 1, data: [] })
- expect(res.bool).to.equal(0n)
- })
-
- it('should remove user access', async function () {
- const res = await uptimeFeedContract.call('has_access', { user: user, data: [] })
- expect(res.bool).to.equal(1n)
-
- await owner.invoke(uptimeFeedContract, 'remove_access', { user: user })
-
- const new_res = await uptimeFeedContract.call('has_access', { user: user, data: [] })
- expect(new_res.bool).to.equal(0n)
- })
- })
-
- describe('Test IAggregator interface using a Proxy', function () {
- let uptimeFeedContract: StarknetContract
- let proxyContract: StarknetContract
-
- before(async function () {
- const uptimeFeedFactory = await starknet.getContractFactory('sequencer_uptime_feed')
- await owner.declare(uptimeFeedFactory)
- uptimeFeedContract = await owner.deploy(uptimeFeedFactory, {
- initial_status: 0,
- owner_address: num.toBigInt(owner.starknetContract.address),
- })
-
- const proxyFactory = await starknet.getContractFactory('aggregator_proxy')
- await owner.declare(proxyFactory)
- proxyContract = await owner.deploy(proxyFactory, {
- owner: num.toBigInt(owner.starknetContract.address),
- address: num.toBigInt(uptimeFeedContract.address),
- })
-
- // proxy contract needs to have access to uptimeFeedContract
- await owner.invoke(uptimeFeedContract, 'add_access', { user: proxyContract.address })
- })
-
- it('should block access when using an account without access', async function () {
- const accWithoutAccess = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: accWithoutAccess.address, amount: 1e21 }])
- await accWithoutAccess.deployAccount()
- await expectInvokeError(
- accWithoutAccess.invoke(proxyContract, 'latest_round_data'),
- 'SimpleReadAccessController: address does not have access',
- )
- })
-
- it('should respond via an aggregator_proxy contract', async function () {
- {
- const res = await proxyContract.call('latest_round_data')
- expect(res.round.answer).to.equal(0n)
- }
-
- {
- const res = await proxyContract.call('description')
- expect(res.description).to.equal(
- 134626335741441605527772921271890603575702899782138692259993464692975953252n,
- )
- }
-
- {
- const res = await proxyContract.call('decimals')
- expect(res.decimals).to.equal(0n)
- }
-
- // TODO: enable access check and assert correct behaviour
- })
- })
-})
diff --git a/contracts/test/l1-l2-messaging.ts b/contracts/test/l1-l2-messaging.ts
new file mode 100644
index 0000000..b27b585
--- /dev/null
+++ b/contracts/test/l1-l2-messaging.ts
@@ -0,0 +1,103 @@
+import { ETH_DEVNET_URL, STARKNET_DEVNET_URL } from './constants'
+
+//
+// Docs: https://github.com/0xSpaceShard/starknet-devnet-rs/blob/main/contracts/l1-l2-messaging/README.md#ethereum-setup
+//
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/models.rs#L23
+ */
+export type PostmanLoadL1MessagingContract = Readonly<{
+ networkUrl?: string
+ address?: string
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/models.rs#L132
+ */
+export type MessagingLoadAddress = Readonly<{
+ messaging_contract_address: string
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/endpoints/postman.rs#L12
+ */
+export const loadL1MessagingContract = async (
+ params?: PostmanLoadL1MessagingContract,
+): Promise => {
+ const res = await fetch(`${STARKNET_DEVNET_URL}/postman/load_l1_messaging_contract`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ network_url: params?.networkUrl ?? ETH_DEVNET_URL,
+ address: params?.address,
+ }),
+ })
+
+ const result = await res.json()
+ if (result.error != null) {
+ throw new Error(result.error)
+ }
+ return result
+}
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/models.rs#L127
+ */
+export type FlushParameters = Readonly<{
+ dryRun?: boolean
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-types/src/rpc/messaging.rs#L52
+ */
+export type MessageToL1 = Readonly<{
+ from_address: string
+ to_address: string
+ payload: string[]
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-types/src/rpc/messaging.rs#L14
+ */
+export type MessageToL2 = Readonly<{
+ l2_contract_address: string
+ entry_point_selector: string
+ l1_contract_address: string
+ payload: string
+ paid_fee_on_l1: string
+ nonce: string
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/models.rs#L120
+ */
+export type FlushedMessages = Readonly<{
+ messages_to_l1: MessageToL1[]
+ messages_to_l2: MessageToL2[]
+ generated_l2_transactions: string[]
+ l1_provider: string
+}>
+
+/*
+ * https://github.com/0xSpaceShard/starknet-devnet-rs/blob/7e5ff351198f799816c1857c1048bf8ee7f89428/crates/starknet-devnet-server/src/api/http/endpoints/postman.rs#L26
+ */
+export const flush = async (params?: FlushParameters): Promise => {
+ const res = await fetch(`${STARKNET_DEVNET_URL}/postman/flush`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ dry_run: params?.dryRun ?? false,
+ }),
+ })
+
+ const result = await res.json()
+ if (result.error != null) {
+ throw new Error(result.error)
+ }
+ return result
+}
diff --git a/contracts/test/ocr2/aggregator.test.ts b/contracts/test/ocr2/aggregator.test.ts
index f88480b..a8efd7b 100644
--- a/contracts/test/ocr2/aggregator.test.ts
+++ b/contracts/test/ocr2/aggregator.test.ts
@@ -1,144 +1,126 @@
+import { fetchStarknetAccount, getStarknetContractArtifacts } from '../utils'
+import { bytesToFelts } from '@plugin/starknet-gauntlet'
+import { STARKNET_DEVNET_URL, TIMEOUT } from '../constants'
+import * as account from '../account'
import { assert, expect } from 'chai'
-import BN from 'bn.js'
-import { starknet } from 'hardhat'
-import { ec, hash, num, uint256 } from 'starknet'
-import { Account, StarknetContract, StarknetContractFactory } from 'hardhat/types/runtime'
-import { shouldBehaveLikeOwnableContract } from '../access/behavior/ownable'
-import { TIMEOUT } from '../constants'
-import { account, expectInvokeErrorMsg } from '@pluginv3.0/starknet'
-
-interface Oracle {
- signer: Uint8Array
+import {
+ BigNumberish,
+ ParsedStruct,
+ LibraryError,
+ RpcProvider,
+ Contract,
+ CallData,
+ Account,
+ Uint256,
+ cairo,
+ hash,
+ num,
+ ec,
+} from 'starknet'
+
+type Oracle = Readonly<{
+ // hex string
+ signer: string
transmitter: Account
-}
-
-const CHUNK_SIZE = 31
+}>
// Observers - max 31 oracles or 31 bytes
const OBSERVERS_MAX = 31
const OBSERVERS_HEX = '0x00010203000000000000000000000000000000000000000000000000000000'
-const INT128_MIN = BigInt(-2) ** BigInt(128 - 1)
-const INT128_MAX = BigInt(2) ** BigInt(128 - 1) - BigInt(1)
-
-function encodeBytes(data: Uint8Array): string[] {
- let felts = []
-
- // prefix with len
- let len = data.byteLength
- felts.push(num.toBigInt(len).toString())
-
- // chunk every 31 bytes
- for (let i = 0; i < data.length; i += CHUNK_SIZE) {
- const chunk = data.slice(i, i + CHUNK_SIZE)
- // cast to int
- felts.push(new BN(chunk, 'be').toString())
- }
- return felts
-}
-
-function decodeBytes(felts: BN[]): Uint8Array {
- let data = []
-
- // TODO: validate len > 1
-
- // TODO: validate it fits into 54 bits
- let length = felts.shift()?.toNumber()!
+const UINT128_MAX = BigInt(2) ** BigInt(128) - BigInt(1)
- for (const felt of felts) {
- let chunk = felt.toArray('be', Math.min(CHUNK_SIZE, length))
- data.push(...chunk)
-
- length -= chunk.length
- }
-
- return new Uint8Array(data)
-}
-
-describe('aggregator.cairo', function () {
+describe('Aggregator', function () {
this.timeout(TIMEOUT)
+ const provider = new RpcProvider({ nodeUrl: STARKNET_DEVNET_URL })
const opts = account.makeFunderOptsFromEnv()
const funder = new account.Funder(opts)
- let aggregatorFactory: StarknetContractFactory
-
+ let aggregator: Contract
+ let token: Contract
let owner: Account
- let token: StarknetContract
- let aggregator: StarknetContract
-
- let minAnswer = 2
- let maxAnswer = 1000000000
-
- let f = 1
- let n = 3 * f + 1
- let oracles: Oracle[] = []
- let config_digest: number
- let answer: string
+ const maxAnswer = 1000000000
+ const minAnswer = 2
+ const f = 1
+ const n = 3 * f + 1
+ const oracles: Oracle[] = []
+ let config_digest: string
before(async () => {
- // assumes contract.cairo and events.cairo has been compiled
- aggregatorFactory = await starknet.getContractFactory('ocr2/aggregator')
-
- // can also be declared as
- // account = (await starknet.deployAccount("OpenZeppelin")) as OpenZeppelinAccount
- // if imported from hardhat/types/runtime"
- owner = await starknet.OpenZeppelinAccount.createAccount()
-
+ // Sets up the owner account
+ owner = await fetchStarknetAccount()
await funder.fund([{ account: owner.address, amount: 1e21 }])
- await owner.deployAccount()
-
- const tokenFactory = await starknet.getContractFactory('link_token')
- await owner.declare(tokenFactory)
- token = await owner.deploy(tokenFactory, { owner: owner.starknetContract.address })
-
- await owner.invoke(token, 'permissionedMint', {
- account: owner.starknetContract.address,
- amount: uint256.bnToUint256(100_000_000_000),
- })
-
- await owner.declare(aggregatorFactory)
-
- aggregator = await owner.deploy(aggregatorFactory, {
- owner: BigInt(owner.starknetContract.address),
- link: BigInt(token.address),
- min_answer: minAnswer, // TODO: toFelt() to correctly wrap negative ints
- max_answer: maxAnswer, // TODO: toFelt() to correctly wrap negative ints
- billing_access_controller: 0, // TODO: billing AC
- decimals: 8,
- description: starknet.shortStringToBigInt('FOO/BAR'),
+ console.log('Owner account has been funded')
+
+ // Declares and deploys the PLI token contract
+ const ddToken = await owner.declareAndDeploy({
+ ...getStarknetContractArtifacts('LinkToken'),
+ constructorCalldata: CallData.compile({
+ minter: owner.address,
+ owner: owner.address,
+ }),
})
+ console.log(`Successfully deployed LinkToken: ${ddToken.deploy.address}`)
- console.log(`Deployed 'aggregator.cairo': ${aggregator.address}`)
-
- let futures = []
- let generateOracle = async () => {
- let transmitter = await starknet.OpenZeppelinAccount.createAccount()
+ // Creates a starknet contract instance for token
+ const { abi: tokenAbi } = await provider.getClassByHash(ddToken.declare.class_hash)
+ token = new Contract(tokenAbi, ddToken.deploy.address, provider)
- await funder.fund([{ account: transmitter.address, amount: 1e21 }])
- await transmitter.deployAccount()
-
- return {
- signer: ec.starkCurve.utils.randomPrivateKey(),
- transmitter,
- // payee
- }
- }
- for (let i = 0; i < n; i++) {
- futures.push(generateOracle())
- }
- oracles = await Promise.all(futures)
-
- let onchain_config: number[] = []
- let offchain_config_version = 2
- let offchain_config = new Uint8Array([1])
- let offchain_config_encoded = encodeBytes(offchain_config)
- console.log('Encoded offchain_config: %O', encodeBytes(offchain_config))
+ // Funds the owner account with some PLI
+ await owner.execute(
+ token.populate('permissioned_mint', {
+ account: owner.address,
+ amount: cairo.uint256(100_000_000_000n),
+ }),
+ )
+ console.log('Successfully funded owner account with PLI')
+
+ // Performs the following in parallel:
+ // Deploys the aggregator contract
+ // Populates the oracles array with devnet accounts
+ const [ddAggregator] = await Promise.all([
+ // Declares and deploys the aggregator
+ owner.declareAndDeploy({
+ ...getStarknetContractArtifacts('Aggregator'),
+ constructorCalldata: CallData.compile({
+ owner: owner.address,
+ link: token.address,
+ min_answer: minAnswer, // TODO: toFelt() to correctly wrap negative ints
+ max_answer: maxAnswer, // TODO: toFelt() to correctly wrap negative ints
+ billing_access_controller: 0, // TODO: billing AC
+ decimals: 8,
+ description: 0,
+ }),
+ }),
- let config = {
+ // Populates the oracles array with devnet accounts
+ ...Array.from({ length: n }).map(async (_, i) => {
+ // account index 0 is taken by the owner account, so we need to offset by 1
+ const transmitter = await fetchStarknetAccount({ accountIndex: i + 1 })
+ await funder.fund([{ account: transmitter.address, amount: 1e21 }])
+ oracles.push({
+ signer: '0x' + Buffer.from(ec.starkCurve.utils.randomPrivateKey()).toString('hex'),
+ transmitter,
+ // payee
+ })
+ }),
+ ])
+ console.log(`Successfully deployed Aggregator: ${ddAggregator.deploy.address}`)
+
+ // Creates a starknet contract instance for aggregator
+ const { abi: aggregatorAbi } = await provider.getClassByHash(ddAggregator.declare.class_hash)
+ aggregator = new Contract(aggregatorAbi, ddAggregator.deploy.address, provider)
+
+ // Defines the offchain config
+ const onchain_config = new Array()
+ const offchain_config = new Uint8Array([1])
+ const offchain_config_encoded = bytesToFelts(offchain_config)
+ const offchain_config_version = 2
+ const config = {
oracles: oracles.map((oracle) => {
return {
signer: ec.starkCurve.getStarkKey(oracle.signer),
- transmitter: oracle.transmitter.starknetContract.address,
+ transmitter: oracle.transmitter.address,
}
}),
f,
@@ -146,158 +128,225 @@ describe('aggregator.cairo', function () {
offchain_config_version,
offchain_config: offchain_config_encoded,
}
- await owner.invoke(aggregator, 'set_config', config)
- console.log('Config: %O', config)
+ console.log('Encoded offchain_config: %O', offchain_config_encoded)
- let result = await aggregator.call('latest_config_details')
- config_digest = result.config_digest
- console.log(`Config digest: 0x${config_digest.toString(16)}`)
+ // Sets the billing config
+ await owner.execute(
+ aggregator.populate('set_billing', {
+ config: {
+ observation_payment_gjuels: 1,
+ transmission_payment_gjuels: 1,
+ gas_base: 1,
+ gas_per_signature: 1,
+ },
+ }),
+ )
- // Immitate the fetch done by relay to confirm latest_config_details_works
- let block = await starknet.getBlock({ blockNumber: result.block_number })
- let events = block.transaction_receipts[0].events
+ // Sets the OCR config
+ await owner.execute(aggregator.populate('set_config', config))
+ console.log('Config: %O', config)
- assert.isNotEmpty(events)
- assert.equal(events.length, 2)
- console.log("Log raw 'ConfigSet' event: %O", events[0])
+ // Gets the config details as bigints:
+ //
+ // result["0"] = config_count
+ // result["1"] = block_number
+ // result["2"] = config_digest
+ //
+ const result = await aggregator.latest_config_details()
+ const blockNumber = Number(result['1']) // we receive a bigint, but getBlock() assumes bigint = block hash, number = block number
+ const configDigest = result['2']
+ console.log(`Config digest: ${configDigest.toString(16)}`)
+ console.log(`Block number: ${blockNumber.toString(16)}`)
+ config_digest = configDigest
- const decodedEvents = aggregator.decodeEvents(events)
- assert.isNotEmpty(decodedEvents)
- assert.equal(decodedEvents.length, 1)
- console.log("Log decoded 'ConfigSet' event: %O", decodedEvents[0])
+ // Immitate the fetch done by relay to confirm latest_config_details_works
+ const block = await provider.getBlock(blockNumber)
+ const txHash = block.transactions.at(0)
+ if (txHash == null) {
+ assert.fail('unexpectedly found no transacitons')
+ }
- let e = decodedEvents[0]
- assert.equal(e.name, 'ConfigSet')
- })
+ // Gets the transaction receipt
+ const receipt = await provider.waitForTransaction(txHash)
- shouldBehaveLikeOwnableContract(async () => {
- const alice = owner
- const bob = await starknet.OpenZeppelinAccount.createAccount()
+ // Checks that the receipt has events to decode
+ const events = receipt.events
+ const event = events.at(0)
+ if (event == null) {
+ assert.fail('unexpectedly received no events')
+ } else {
+ console.log("Log raw 'ConfigSet' event: %O", event)
+ }
- await funder.fund([{ account: bob.address, amount: 1e21 }])
- await bob.deployAccount()
+ // Decodes the events
+ const decodedEvents = aggregator.parseEvents(receipt)
+ const decodedEvent = decodedEvents.at(0)
+ if (decodedEvent == null) {
+ assert.fail('unexpectedly received no decoded events')
+ } else {
+ console.log("Log decoded 'ConfigSet' event: %O", decodedEvent)
+ }
- return { ownable: aggregator, alice, bob }
+ // Double checks that the ConfigSet event exists in the decoded event payload
+ assert.isTrue(Object.prototype.hasOwnProperty.call(decodedEvent, 'ConfigSet'))
})
describe('OCR aggregator behavior', function () {
- let transmit = async (epoch_and_round: number, answer: num.BigNumberish): Promise => {
- let extra_hash = 1
- let observation_timestamp = 1
- let juels_per_fee_coin = 1
- let gas_price = 1
-
- let observers_buf = Buffer.alloc(31)
- let observations = []
-
- for (const [index, _] of oracles.entries()) {
- observers_buf[index] = index
+ const transmit = async (epochAndRound: number, answer: num.BigNumberish) => {
+ // Defines helper variables
+ const observations = new Array()
+ const observersBuf = Buffer.alloc(31)
+ const observationTimestamp = 1
+ const juelsPerFeeCoin = 1
+ const extraHash = 1
+ const gasPrice = 1
+
+ // Updates the observer state
+ for (let i = 0; i < oracles.length; i++) {
+ observersBuf[i] = i
observations.push(answer)
}
- // convert to a single value that will be decoded by toBN
- let observers = `0x${observers_buf.toString('hex')}`
+ // Converts observersBuf to a single value that will be decoded by toBN
+ const observers = `0x${observersBuf.toString('hex')}`
assert.equal(observers, OBSERVERS_HEX)
+ // Defines report data
const reportData = [
// report_context
config_digest,
- epoch_and_round,
- extra_hash,
+ epochAndRound,
+ extraHash,
// raw_report
- observation_timestamp,
+ observationTimestamp,
observers,
observations.length,
...observations,
- juels_per_fee_coin,
- gas_price,
+ juelsPerFeeCoin,
+ gasPrice,
]
- let reportDigest = hash.computeHashOnElements(reportData)
+
+ // Hashes the report data
+ const reportDigest = hash.computeHashOnElements(reportData)
console.log('Report data: %O', reportData)
console.log(`Report digest: ${reportDigest}`)
+ // Generates report signatures
console.log('Report signatures - START')
- let signatures = []
- for (let { signer } of oracles.slice(0, f + 1)) {
- let signature = ec.starkCurve.sign(reportDigest, signer)
- let r = signature.r
- let s = signature.s
- const pubKey = num.toHex(ec.starkCurve.getStarkKey(signer))
- signatures.push({ r, s, public_key: pubKey })
- console.log({ pubKey, privKey: signer, r, s })
+ const signatures = []
+ for (const { signer } of oracles.slice(0, f + 1)) {
+ const signature = ec.starkCurve.sign(reportDigest, signer)
+ const { r, s } = signature
+ const starkKey = ec.starkCurve.getStarkKey(signer)
+ const pubKey = '0x' + Buffer.from(ec.starkCurve.getPublicKey(signer)).toString('hex')
+ signatures.push({ r, s, public_key: starkKey })
+ console.log({
+ starkKey,
+ pubKey,
+ privKey: signer,
+ r,
+ s,
+ })
}
console.log('Report signatures - END\n')
- const transmitter = oracles[0].transmitter
- return await transmitter.invoke(aggregator, 'transmit', {
- report_context: {
- config_digest,
- epoch_and_round,
- extra_hash,
- },
- observation_timestamp,
- observers,
- observations,
- juels_per_fee_coin,
- gas_price,
- signatures,
- })
- }
+ // Gets the first transmitter
+ const transmitter = oracles.at(0)?.transmitter
+ if (transmitter == null) {
+ assert.fail('no oracles exist')
+ }
- it("should 'set_billing' successfully", async () => {
- await owner.invoke(aggregator, 'set_billing', {
- config: {
- observation_payment_gjuels: 1,
- transmission_payment_gjuels: 5,
- gas_base: 1,
- gas_per_signature: 1,
- },
- })
- })
+ // Executes the transmit function on the aggregator contract
+ return await transmitter.execute(
+ aggregator.populate('transmit', {
+ report_context: {
+ config_digest,
+ epoch_and_round: epochAndRound,
+ extra_hash: extraHash,
+ },
+ observation_timestamp: observationTimestamp,
+ observers,
+ observations,
+ juels_per_fee_coin: juelsPerFeeCoin,
+ gas_price: gasPrice,
+ signatures,
+ }),
+ )
+ }
it("should emit 'NewTransmission' event on transmit", async () => {
- const txHash = await transmit(1, 99)
- const receipt = await starknet.getTransactionReceipt(txHash)
+ // Calls the transmit function
+ const { transaction_hash } = await transmit(1, 99)
+ const receipt = await provider.getTransactionReceipt(transaction_hash)
+ // Double checks that some events were emitted
assert.isNotEmpty(receipt.events)
console.log("Log raw 'NewTransmission' event: %O", receipt.events[0])
- const decodedEvents = aggregator.decodeEvents(receipt.events)
- assert.isNotEmpty(decodedEvents)
- console.log("Log decoded 'NewTransmission' event: %O", decodedEvents[0])
-
- const e = decodedEvents[0]
- const transmitter = oracles[0].transmitter.address
+ // Decodes the events
+ const decodedEvents = aggregator.parseEvents(receipt)
+ const decodedEvent = decodedEvents.at(0)
+ if (decodedEvent == null) {
+ assert.fail('unexpectedly received no decoded events')
+ } else {
+ console.log("Log decoded 'NewTransmission' event: %O", decodedEvent)
+ }
- assert.equal(e.name, 'NewTransmission')
- assert.equal(e.data.round_id, 1n)
- assert.equal(e.data.observation_timestamp, 1n)
- assert.equal(e.data.epoch_and_round, 1n)
+ // Validates the decoded event
+ const e = decodedEvent['NewTransmission']
+ assert.isTrue(Object.prototype.hasOwnProperty.call(decodedEvent, 'NewTransmission'))
+ assert.equal(e.round_id, 1n)
+ assert.equal(e.observation_timestamp, 1n)
+ assert.equal(e.epoch_and_round, 1n)
// assert.equal(e.data.reimbursement, 0n)
- const len = 32 * 2 // 32 bytes (hex)
-
// NOTICE: Leading zeros are trimmed for an encoded felt (number).
// To decode, the raw felt needs to be start padded up to max felt size (252 bits or < 32 bytes).
- const hexPadStart = (data: number | bigint, len: number) => {
+ const hexPadStart = (
+ data: BigNumberish | Uint256 | ParsedStruct | BigNumberish[],
+ len: number,
+ ) => {
return `0x${data.toString(16).padStart(len, '0')}`
}
- expect(hexPadStart(e.data.transmitter, len)).to.hexEqual(transmitter)
+ // Validates the transmitter
+ const transmitterAddr = oracles[0].transmitter.address
+ const len = 32 * 2 // 32 bytes (hex)
+ expect(hexPadStart(e.transmitter, len)).to.hexEqual(transmitterAddr)
+ // Validates the observers and observations
const lenObservers = OBSERVERS_MAX * 2 // 31 bytes (hex)
- assert.equal(hexPadStart(e.data.observers, lenObservers), OBSERVERS_HEX)
- assert.equal(e.data.observations_len, 4n)
+ assert.equal(hexPadStart(e.observers, lenObservers), OBSERVERS_HEX)
+ if (Array.isArray(e.observations)) {
+ assert.equal(e.observations.length, 4)
+ } else {
+ assert.fail(
+ `property 'observations' on NewTransmission event is not an array: ${JSON.stringify(
+ e,
+ null,
+ 2,
+ )}`,
+ )
+ }
- assert.equal(hexPadStart(e.data.config_digest, len), hexPadStart(config_digest, len))
+ // Validates the config digest
+ assert.equal(hexPadStart(e.config_digest, len), config_digest)
})
it('should transmit correctly', async () => {
await transmit(2, 99)
- let { round } = await aggregator.call('latest_round_data')
- assert.equal(round.round_id, 2)
- assert.equal(round.answer, 99)
+ // Gets the latest round details as a map from string to bigint:
+ //
+ // result["round_id"] = 2n
+ // result["answer"] = 99n
+ // result["block_num"] = 8n
+ // result["started_at"] = 1n
+ // result["updated_at"] = 1710802726n
+ //
+ const round = await aggregator.latest_round_data()
+ assert.equal(round['round_id'], 2n)
+ assert.equal(round['answer'], 99n)
// await transmit(3, -10) // TODO: toFelt() to correctly wrap negative ints
// ;({ round } = await aggregator.call('latest_round_data'))
@@ -307,162 +356,85 @@ describe('aggregator.cairo', function () {
try {
await transmit(4, 1)
expect.fail()
- } catch (err: any) {
+ } catch (err) {
// Round should be unchanged
- let { round: new_round } = await aggregator.call('latest_round_data')
- assert.deepEqual(round, new_round)
+ const newRound = await aggregator.latest_round_data()
+ assert.deepEqual(round, newRound)
}
})
- it('should transmit with max_int_128bit correctly', async () => {
- answer = BigInt(INT128_MAX).toString(10)
+ it('should transmit with max u128 value correctly', async () => {
try {
- await transmit(4, answer) // TODO: toFelt()
- expect.fail()
- } catch (error: any) {
- const matches = error?.message.match(/Error message: (.+?)\n/g)
- if (!matches) {
- console.log('answer is in int128 range but not in min-max range')
+ await transmit(4, UINT128_MAX)
+ assert.fail('expected an error')
+ } catch (err) {
+ if (err instanceof LibraryError) {
+ expect(err.message).to.contain('median is out of min-max range')
+ } else {
+ assert.fail('expected a starknet LibraryError')
}
}
-
- try {
- const tooBig = INT128_MAX + 1n
- answer = BigInt(tooBig).toString(10)
- await transmit(4, answer)
- expect.fail()
- } catch (err: any) {
- expectInvokeErrorMsg(
- err?.message,
- `Error message: Aggregator: value not in int128 range: ${answer}\n`,
- )
- }
- })
-
- // it('should transmit with min_int_128bit correctly', async () => {
- // answer = BigInt(INT128_MIN).toString(10)
- // try {
- // await transmit(4, answer) // TODO: toFelt()
- // } catch (err: any) {
- // const matches = err?.message.match(/Error message: (.+?)\n/g)
- // if (!matches) {
- // console.log('answer is in int128 range but not in min-max range')
- // }
- // }
- //
- // try {
- // const tooBig = INT128_MIN - 1n
- // answer = BigInt(tooBig).toString(10)
- // await transmit(4, answer) // TODO: toFelt()
- // expect.fail()
- // } catch (err: any) {
- // expectInvokeErrorMsg(
- // err?.message,
- // `Error message: Aggregator: value not in int128 range: ${answer}\n`,
- // )
- // }
- // })
-
- it('payee management', async () => {
- let payees = oracles.map((oracle) => ({
- transmitter: oracle.transmitter.starknetContract.address,
- payee: oracle.transmitter.starknetContract.address, // reusing transmitter acocunts as payees for simplicity
- }))
- // call set_payees, should succeed because all payees are zero
- await owner.invoke(aggregator, 'set_payees', { payees })
- // call set_payees, should succeed because values are unchanged
- await owner.invoke(aggregator, 'set_payees', { payees })
-
- let oracle = oracles[0].transmitter
- let transmitter = oracle.starknetContract.address
- let payee = transmitter
-
- let proposed_oracle = oracles[1].transmitter
- let proposed_transmitter = proposed_oracle.starknetContract.address
- let proposed_payee = proposed_transmitter
-
- // can't transfer to self
- try {
- await oracle.invoke(aggregator, 'transfer_payeeship', {
- transmitter,
- proposed: payee,
- })
- expect.fail()
- } catch (err: any) {
- // TODO: expect(err.message).to.contain("");
- }
-
- // only payee can transfer
- try {
- await proposed_oracle.invoke(aggregator, 'transfer_payeeship', {
- transmitter,
- proposed: proposed_payee,
- })
- expect.fail()
- } catch (err: any) {}
-
- // successful transfer
- await oracle.invoke(aggregator, 'transfer_payeeship', {
- transmitter,
- proposed: proposed_payee,
- })
-
- // only proposed payee can accept
- try {
- await oracle.invoke(aggregator, 'accept_payeeship', { transmitter })
- expect.fail()
- } catch (err: any) {}
-
- // successful accept
- await proposed_oracle.invoke(aggregator, 'accept_payeeship', {
- transmitter,
- })
})
it('payments and withdrawals', async () => {
- let oracle = oracles[0]
- // NOTE: previous test changed oracle0's payee to oracle1
- let payee = oracles[1].transmitter
- aggregator.call
- let { amount: owed } = await aggregator.call('owed_payment', {
- transmitter: oracle.transmitter.starknetContract.address,
- })
- // several rounds happened so we are owed payment
- assert.ok(owed > 0)
+ // set up payees
+ await owner.execute(
+ aggregator.populate('set_payees', {
+ payees: oracles.map((oracle) => ({
+ transmitter: oracle.transmitter.address,
+ payee: oracle.transmitter.address, // reusing transmitter acocunts as payees for simplicity
+ })),
+ }),
+ )
+
+ // Several rounds happened so we are owed payment
+ //
+ // The aggregator.owed_payment call returns a bigint
+ //
+ const payee = oracles[0].transmitter
+ const owed1 = await aggregator.owed_payment(payee.address)
+ assert.ok(owed1 > 0n)
+
+ const availableToValue = ([is_negative, abs_difference]: [boolean, bigint]): bigint => {
+ return is_negative ? -abs_difference : abs_difference
+ }
// no funds on contract, so no PLI available for payment
- let { available } = await aggregator.call('link_available_for_payment')
- assert.ok(available < 0) // should be negative: we owe payments
+ //
+ // The aggregator.link_available_for_payment call returns a map:
+ //
+ // result['0'] = is negative (e.g. true)
+ // result['1'] = absolute difference (e.g. 10000000006n)
+ //
+ let result = await aggregator.link_available_for_payment()
+ assert.ok(availableToValue([result['0'], result['1']]) < 0) // should be negative: we owe payments
// deposit PLI to contract
- await owner.invoke(token, 'transfer', {
- recipient: aggregator.address,
- amount: uint256.bnToUint256(100_000_000_000),
- })
+ await owner.execute(
+ token.populate('transfer', {
+ recipient: aggregator.address,
+ amount: cairo.uint256(100_000_000_000n),
+ }),
+ )
// we have enough funds available now
- available = (await aggregator.call('link_available_for_payment')).available
- assert.ok(available > 0)
+ result = await aggregator.link_available_for_payment()
+ assert.ok(availableToValue([result['0'], result['1']]) > 0)
// attempt to withdraw the payment
- await payee.invoke(aggregator, 'withdraw_payment', {
- transmitter: oracle.transmitter.starknetContract.address,
- })
+ await payee.execute(
+ aggregator.populate('withdraw_payment', {
+ transmitter: payee.address,
+ }),
+ )
// balance as transferred to payee
- let { balance } = await token.call('balanceOf', {
- account: payee.starknetContract.address,
- })
-
- assert.ok(num.toBigInt(owed) === uint256.uint256ToBN(balance))
+ const balance = await token.balance_of(payee.address)
+ assert.ok(owed1 === balance)
// owed payment is now zero
- {
- let { amount: owed } = await aggregator.call('owed_payment', {
- transmitter: oracle.transmitter.starknetContract.address,
- })
- assert.ok(owed == 0)
- }
+ const owed2 = await aggregator.owed_payment(payee.address)
+ assert.ok(owed2 === 0n)
})
})
})
diff --git a/contracts/test/ocr2/aggregator_proxy.test.ts b/contracts/test/ocr2/aggregator_proxy.test.ts
deleted file mode 100644
index 32af3db..0000000
--- a/contracts/test/ocr2/aggregator_proxy.test.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { assert } from 'chai'
-import { starknet } from 'hardhat'
-import { num } from 'starknet'
-import { Account, StarknetContract, StarknetContractFactory } from 'hardhat/types/runtime'
-import { TIMEOUT } from '../constants'
-import { shouldBehaveLikeOwnableContract } from '../access/behavior/ownable'
-import { account } from '@pluginv3.0/starknet'
-
-describe('aggregator_proxy.cairo', function () {
- this.timeout(TIMEOUT)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
- let aggregatorContractFactory: StarknetContractFactory
- let proxyContractFactory: StarknetContractFactory
-
- let owner: Account
- let aggregator: StarknetContract
- let proxy: StarknetContract
-
- before(async function () {
- // assumes contract.cairo and events.cairo has been compiled
- aggregatorContractFactory = await starknet.getContractFactory('ocr2/mocks/MockAggregator')
- proxyContractFactory = await starknet.getContractFactory('ocr2/aggregator_proxy')
-
- owner = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: owner.address, amount: 1e21 }])
- await owner.deployAccount()
-
- await owner.declare(aggregatorContractFactory)
- aggregator = await owner.deploy(aggregatorContractFactory, { decimals: 8 })
-
- await owner.declare(proxyContractFactory)
-
- proxy = await owner.deploy(proxyContractFactory, {
- owner: owner.address,
- address: aggregator.address,
- })
-
- console.log(proxy.address)
- })
-
- shouldBehaveLikeOwnableContract(async () => {
- const alice = owner
- const bob = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: bob.address, amount: 1e21 }])
- await bob.deployAccount()
- return { ownable: proxy, alice, bob }
- })
-
- describe('proxy behaviour', function () {
- it('works', async () => {
- // insert round into the mock
- await owner.invoke(aggregator, 'set_latest_round_data', {
- answer: 10,
- block_num: 1,
- observation_timestamp: 9,
- transmission_timestamp: 8,
- })
-
- // query latest round
- let { round } = await proxy.call('latest_round_data')
- // TODO: split_felt the round_id and check phase=1 round=1
- assert.equal(round.answer, '10')
- assert.equal(round.block_num, '1')
- assert.equal(round.started_at, '9')
- assert.equal(round.updated_at, '8')
-
- // insert a second ocr2 aggregator
- let new_aggregator = await owner.deploy(aggregatorContractFactory, { decimals: 8 })
-
- // insert round into the mock
- await owner.invoke(new_aggregator, 'set_latest_round_data', {
- answer: 12,
- block_num: 2,
- observation_timestamp: 10,
- transmission_timestamp: 11,
- })
-
- // propose it to the proxy
- await owner.invoke(proxy, 'propose_aggregator', {
- address: new_aggregator.address,
- })
-
- // query latest round, it should still point to the old aggregator
- round = (await proxy.call('latest_round_data')).round
- assert.equal(round.answer, '10')
-
- // but the proposed round should be newer
- round = (await proxy.call('proposed_latest_round_data')).round
- assert.equal(round.answer, '12')
-
- // confirm the new aggregator
- await owner.invoke(proxy, 'confirm_aggregator', {
- address: new_aggregator.address,
- })
-
- const phase_aggregator = await proxy.call('aggregator', {})
- assert.equal(phase_aggregator.aggregator, num.toBigInt(new_aggregator.address))
-
- const phase_id = await proxy.call('phase_id', {})
- assert.equal(phase_id.phase_id, 2n)
-
- // query latest round, it should now point to the new aggregator
- round = (await proxy.call('latest_round_data')).round
- assert.equal(round.answer, '12')
- })
- })
-})
diff --git a/contracts/test/setup.ts b/contracts/test/setup.ts
new file mode 100644
index 0000000..71f9d02
--- /dev/null
+++ b/contracts/test/setup.ts
@@ -0,0 +1,94 @@
+import * as path from 'node:path'
+import * as fs from 'node:fs'
+
+function findCommonPrefix(path1: string, path2: string): string {
+ const segments1 = path1.split(path.sep)
+ const segments2 = path2.split(path.sep)
+
+ const minLength = Math.min(segments1.length, segments2.length)
+ const commonSegments = []
+
+ for (let i = 0; i < minLength; i++) {
+ if (segments1[i] === segments2[i]) {
+ commonSegments.push(segments1[i])
+ } else {
+ break
+ }
+ }
+
+ return commonSegments.join(path.sep)
+}
+
+function toCamelCase(str: string): string {
+ return str
+ .replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
+ .replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
+ .replace(/(^| )([a-z])/g, (_, __, letter) => letter.toUpperCase())
+ .replace(/ /g, '')
+}
+
+function findCairoFiles(dir: string): string[] {
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
+ const filePaths = entries.flatMap((entry) => {
+ const entryPath = path.join(dir, entry.name)
+ if (entry.isDirectory()) {
+ return findCairoFiles(entryPath)
+ } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.cairo')) {
+ return [entryPath]
+ } else {
+ return []
+ }
+ })
+ return filePaths
+}
+
+export function prepareHardhatArtifacts() {
+ const hre = require('hardhat')
+
+ const src = hre.config.paths.starknetSources
+ const target = hre.config.paths.starknetArtifacts
+ if (!src || !target) {
+ throw new Error('Missing starknet path config')
+ }
+
+ const root = findCommonPrefix(src, target)
+
+ console.log('Cleaning and regenerating hardhat file structure..')
+ const generatedPath = path.join(target, src.slice(root.length))
+ if (fs.existsSync(generatedPath)) {
+ fs.rmSync(generatedPath, { recursive: true })
+ }
+
+ const cairoFiles = findCairoFiles(src)
+ for (const cairoFile of cairoFiles) {
+ const relativePath = cairoFile
+ const filename = path.basename(relativePath, '.cairo')
+
+ const camelCaseFilename = toCamelCase(filename)
+
+ const sierraFile = `${target}/plugin_${camelCaseFilename}.sierra.json`
+ const casmFile = `${target}/plugin_${camelCaseFilename}.casm.json`
+
+ if (!fs.existsSync(sierraFile) || !fs.existsSync(casmFile)) {
+ continue
+ }
+
+ const subdir = path.dirname(relativePath).slice(root.length)
+ // Create the corresponding directory
+ const targetSubdir = path.join(target, subdir, `${filename}.cairo`)
+ fs.mkdirSync(targetSubdir, { recursive: true })
+
+ // Copy the sierra and casm files. We need to copy instead of symlink
+ // because hardhat-starknet-plugin does fs.lstatSync to check if the file
+ // exists.
+ fs.copyFileSync(sierraFile, `${targetSubdir}/${filename}.json`)
+ fs.copyFileSync(casmFile, `${targetSubdir}/${filename}.casm`)
+
+ // Parse and save the ABI JSON
+ const sierraContent = JSON.parse(fs.readFileSync(sierraFile, 'utf8'))
+ fs.writeFileSync(
+ `${targetSubdir}/${filename}_abi.json`,
+ JSON.stringify(sierraContent.abi, null, 2),
+ )
+ }
+}
diff --git a/contracts/test/token/ERC677/ERC677.test.ts b/contracts/test/token/ERC677/ERC677.test.ts
deleted file mode 100644
index 0dd64f3..0000000
--- a/contracts/test/token/ERC677/ERC677.test.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-import { expect } from 'chai'
-import { starknet } from 'hardhat'
-import { uint256, num } from 'starknet'
-import { Account, StarknetContract, StarknetContractFactory } from 'hardhat/types/runtime'
-import { TIMEOUT } from '../../constants'
-import { account } from '@pluginv3.0/starknet'
-
-describe('ERC677', function () {
- this.timeout(TIMEOUT)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- let receiverFactory: StarknetContractFactory
- let tokenFactory: StarknetContractFactory
- let receiver: StarknetContract
- let sender: Account
- let token: StarknetContract
- let data: (number | bigint)[]
-
- beforeEach(async () => {
- sender = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: sender.address, amount: 1e21 }])
- await sender.deployAccount()
-
- receiverFactory = await starknet.getContractFactory('token677_receiver_mock')
- tokenFactory = await starknet.getContractFactory('link_token')
-
- await sender.declare(receiverFactory)
- receiver = await sender.deploy(receiverFactory, {})
-
- await sender.declare(tokenFactory)
- token = await sender.deploy(tokenFactory, { owner: sender.starknetContract.address })
-
- await sender.invoke(token, 'permissionedMint', {
- account: sender.starknetContract.address,
- amount: uint256.bnToUint256(1000),
- })
-
- await sender.invoke(token, 'transfer', {
- recipient: sender.starknetContract.address,
- amount: uint256.bnToUint256(100),
- })
- const { value: value } = await receiver.call('getSentValue')
- expect(uint256.uint256ToBN(value)).to.deep.equal(num.toBigInt(0))
- })
-
- describe('#transferAndCall(address, uint, bytes)', () => {
- beforeEach(() => {
- data = [100n, 0n, 12]
- })
-
- it('transfers the tokens', async () => {
- let { balance: balance } = await token.call('balanceOf', {
- account: receiver.address,
- })
-
- expect(uint256.uint256ToBN(balance)).to.deep.equal(num.toBigInt(0))
-
- await sender.invoke(token, 'transferAndCall', {
- to: receiver.address,
- value: uint256.bnToUint256(100),
- data: data,
- })
-
- let { balance: balance1 } = await token.call('balanceOf', {
- account: receiver.address,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(100))
- })
-
- it('calls the token fallback function on transfer', async () => {
- await sender.invoke(token, 'transferAndCall', {
- to: receiver.address,
- value: uint256.bnToUint256(100),
- data: data,
- })
-
- const { bool: bool } = await receiver.call('getCalledFallback', {})
- expect(bool).to.deep.equal(1n)
-
- const { address: address } = await receiver.call('getTokenSender', {})
- expect(address).to.equal(BigInt(sender.starknetContract.address))
-
- const { value: sentValue } = await receiver.call('getSentValue')
- expect(uint256.uint256ToBN(sentValue)).to.deep.equal(num.toBigInt(100))
- })
-
- it('transfer succeeds with response', async () => {
- const response = await sender.invoke(token, 'transferAndCall', {
- to: receiver.address,
- value: uint256.bnToUint256(100),
- data: data,
- })
- expect(response).to.exist
- })
-
- it('throws when the transfer fails', async () => {
- try {
- await sender.invoke(token, 'transfer', {
- recipient: receiver.address,
- amount: uint256.bnToUint256(10000),
- })
- expect.fail()
- } catch (error: any) {}
- })
- })
-
- describe('when sending to a contract that is not ERC677 compatible', () => {
- let nonERC677: StarknetContract
-
- beforeEach(async () => {
- const nonERC677Factory = await starknet.getContractFactory('not_erc677_compatible')
-
- await sender.declare(nonERC677Factory)
- nonERC677 = await sender.deploy(nonERC677Factory, {})
-
- data = [1000n, 0n, 12n]
- })
-
- it('throws an error', async () => {
- try {
- await sender.invoke(token, 'transferAndCall', {
- to: nonERC677.address,
- value: uint256.bnToUint256(1000),
- data: data,
- })
- expect.fail()
- } catch (error: any) {
- let { balance: balance1 } = await token.call('balanceOf', {
- account: nonERC677.address,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(0))
- }
- })
-
- it('throws an error when sending to 0 address', async () => {
- try {
- await sender.invoke(token, 'transferAndCall', {
- to: 0,
- value: uint256.bnToUint256(1000),
- data: data,
- })
- expect.fail()
- } catch (error: any) {
- let { balance: balance1 } = await token.call('balanceOf', {
- account: 0,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(0))
- }
- })
- })
-})
diff --git a/contracts/test/token/ERC677/link-receiver.test.ts b/contracts/test/token/ERC677/link-receiver.test.ts
deleted file mode 100644
index d14bc07..0000000
--- a/contracts/test/token/ERC677/link-receiver.test.ts
+++ /dev/null
@@ -1,231 +0,0 @@
-import { expect } from 'chai'
-import { starknet } from 'hardhat'
-import { uint256, hash, num } from 'starknet'
-import { Account, StarknetContract, StarknetContractFactory } from 'hardhat/types/runtime'
-import { TIMEOUT } from '../../constants'
-import { account } from '@pluginv3.0/starknet'
-
-describe('LinkToken', function () {
- this.timeout(TIMEOUT)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- let receiverFactory: StarknetContractFactory
- let linkReceiverFactory: StarknetContractFactory
- let tokenFactory: StarknetContractFactory
- let receiver: StarknetContract
- let recipient: StarknetContract
- let sender: Account
- let owner: Account
- let token: StarknetContract
-
- beforeEach(async () => {
- sender = await starknet.OpenZeppelinAccount.createAccount()
- owner = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([
- { account: sender.address, amount: 1e21 },
- { account: owner.address, amount: 1e21 },
- ])
- await sender.deployAccount()
- await owner.deployAccount()
-
- receiverFactory = await starknet.getContractFactory('token677_receiver_mock')
- tokenFactory = await starknet.getContractFactory('link_token')
-
- await owner.declare(receiverFactory)
- await sender.declare(tokenFactory)
-
- receiver = await sender.deploy(receiverFactory, {})
- token = await owner.deploy(tokenFactory, { owner: owner.starknetContract.address })
-
- await owner.invoke(token, 'permissionedMint', {
- account: owner.starknetContract.address,
- amount: uint256.bnToUint256(1000000000000000),
- })
- })
-
- it('assigns all of the balance to the owner', async () => {
- let { balance: balance } = await token.call('balanceOf', {
- account: owner.starknetContract.address,
- })
- expect(uint256.uint256ToBN(balance).toString()).to.equal('1000000000000000')
- })
-
- describe('#transfer(address,uint256)', () => {
- beforeEach(async () => {
- await owner.invoke(token, 'transfer', {
- recipient: sender.starknetContract.address,
- amount: uint256.bnToUint256(100),
- })
- const { value: sentValue } = await receiver.call('getSentValue')
- expect(uint256.uint256ToBN(sentValue)).to.deep.equal(num.toBigInt(0))
- })
-
- it('does not let you transfer to the null address', async () => {
- try {
- await sender.invoke(token, 'transfer', { recipient: 0, value: uint256.bnToUint256(100) })
- expect.fail()
- } catch (error: any) {
- let { balance: balance1 } = await token.call('balanceOf', {
- account: sender.starknetContract.address,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(100))
- }
- })
-
- // TODO For now it let you transfer to the contract itself
- it.skip('does not let you transfer to the contract itself', async () => {
- try {
- await sender.invoke(token, 'transfer', {
- recipient: token.address,
- amount: uint256.bnToUint256(100),
- })
- expect.fail()
- } catch (error: any) {
- let { balance: balance1 } = await token.call('balanceOf', {
- account: sender.starknetContract.address,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(100))
- }
- })
-
- it('transfers the tokens', async () => {
- let { balance: balance } = await token.call('balanceOf', {
- account: receiver.address,
- })
- expect(uint256.uint256ToBN(balance)).to.deep.equal(num.toBigInt(0))
-
- await sender.invoke(token, 'transfer', {
- recipient: receiver.address,
- amount: uint256.bnToUint256(100),
- })
-
- let { balance: balance1 } = await token.call('balanceOf', {
- account: receiver.address,
- })
- expect(uint256.uint256ToBN(balance1)).to.deep.equal(num.toBigInt(100))
- })
-
- it('does NOT call the fallback on transfer', async () => {
- await sender.invoke(token, 'transfer', {
- recipient: receiver.address,
- amount: uint256.bnToUint256(100),
- })
- const { bool: bool } = await receiver.call('getCalledFallback', {})
- expect(bool).to.deep.equal(0n)
- })
-
- it('transfer succeeds with response', async () => {
- const response = await sender.invoke(token, 'transfer', {
- recipient: receiver.address,
- amount: uint256.bnToUint256(100),
- })
- expect(response).to.exist
- })
- })
-
- describe('#transferAndCall(address,uint256,bytes)', () => {
- const amount = 1000
-
- before(async () => {
- linkReceiverFactory = await starknet.getContractFactory('link_receiver')
- const classHash = await owner.declare(linkReceiverFactory)
- recipient = await owner.deploy(linkReceiverFactory, { class_hash: classHash })
-
- const { remaining: allowance } = await token.call('allowance', {
- owner: owner.starknetContract.address,
- spender: recipient.address,
- })
- expect(uint256.uint256ToBN(allowance)).to.deep.equal(num.toBigInt(0))
-
- let { balance: balance } = await token.call('balanceOf', {
- account: recipient.address,
- })
- expect(uint256.uint256ToBN(balance)).to.deep.equal(num.toBigInt(0))
- })
-
- xit('transfers the amount to the contract and calls the contract function without withdrawl', async () => {
- let selector = hash.getSelectorFromName('callbackWithoutWithdrawl')
- await owner.invoke(token, 'transferAndCall', {
- to: recipient.address,
- value: uint256.bnToUint256(1000),
- data: [selector],
- })
-
- let { balance: balance } = await token.call('balanceOf', {
- account: recipient.address,
- })
- expect(uint256.uint256ToBN(balance)).to.deep.equal(num.toBigInt(amount))
- const { remaining: allowance } = await token.call('allowance', {
- owner: owner.starknetContract.address,
- spender: recipient.address,
- })
- expect(uint256.uint256ToBN(allowance)).to.deep.equal(num.toBigInt(0))
-
- const { bool: fallBack } = await recipient.call('getFallback', {})
- expect(fallBack).to.deep.equal(1n)
-
- const { bool: callData } = await recipient.call('getCallData', {})
- expect(callData).to.deep.equal(1n)
- })
-
- xit('transfers the amount to the contract and calls the contract function with withdrawl', async () => {
- let selector = hash.getSelectorFromName('callbackWithWithdrawl')
- await owner.invoke(token, 'approve', {
- spender: recipient.address,
- amount: uint256.bnToUint256(1000),
- })
-
- const { remaining: allowance } = await token.call('allowance', {
- owner: owner.starknetContract.address,
- spender: recipient.address,
- })
- expect(uint256.uint256ToBN(allowance)).to.deep.equal(num.toBigInt(amount))
-
- await owner.invoke(token, 'transferAndCall', {
- to: recipient.address,
- value: uint256.bnToUint256(1000),
- data: [selector, 0n, 1000n, owner.starknetContract.address, token.address],
- })
-
- let { balance: balance } = await token.call('balanceOf', {
- account: recipient.address,
- })
- expect(uint256.uint256ToBN(balance)).to.deep.equal(num.toBigInt(amount + amount))
-
- const { bool: fallBack } = await recipient.call('getFallback', {})
- expect(fallBack).to.deep.equal(1n)
-
- const { bool: callData } = await recipient.call('getCallData', {})
- expect(callData).to.deep.equal(1n)
-
- const { value: value } = await recipient.call('getTokens', {})
- expect(uint256.uint256ToBN(value)).to.deep.equal(num.toBigInt(amount))
- })
-
- it('transfers the amount to the account and does not call the contract', async () => {
- await owner.invoke(token, 'approve', {
- spender: sender.starknetContract.address,
- amount: uint256.bnToUint256(1000),
- })
-
- const { remaining: allowance } = await token.call('allowance', {
- owner: owner.starknetContract.address,
- spender: sender.starknetContract.address,
- })
- expect(uint256.uint256ToBN(allowance)).to.deep.equal(num.toBigInt(amount))
-
- await owner.invoke(token, 'transferAndCall', {
- to: sender.starknetContract.address,
- value: uint256.bnToUint256(1000),
- data: [],
- })
-
- let { balance: balance2 } = await token.call('balanceOf', {
- account: sender.starknetContract.address,
- })
- expect(uint256.uint256ToBN(balance2)).to.deep.equal(num.toBigInt(amount))
- })
- })
-})
diff --git a/contracts/test/token/starkgate/behavior/ERC20.ts b/contracts/test/token/starkgate/behavior/ERC20.ts
deleted file mode 100644
index 2096ee3..0000000
--- a/contracts/test/token/starkgate/behavior/ERC20.ts
+++ /dev/null
@@ -1,275 +0,0 @@
-import { expect } from 'chai'
-import { StarknetContract, Account } from 'hardhat/types/runtime'
-import { uint256, num } from 'starknet'
-import { TIMEOUT } from '../../../constants'
-import { expectInvokeError } from '@pluginv3.0/starknet/src/utils'
-
-export type BeforeFn = () => Promise
-export type TestData = {
- token: StarknetContract
- owner: Account
- alice: Account
- bob: Account
-}
-
-const addresses = (t: TestData) => ({
- owner: t.owner.starknetContract.address,
- bob: t.bob.starknetContract.address,
- alice: t.alice.starknetContract.address,
-})
-
-const expectERC20Balance = async (token: StarknetContract, acc: Account, expected: number) => {
- const { balance: raw } = await token.call('balanceOf', {
- account: acc.starknetContract.address,
- })
- const balance = uint256.uint256ToBN(raw)
- expect(balance).to.deep.equal(num.toBigInt(expected))
-}
-
-const expectERC20TotalSupply = async (token: StarknetContract, expected: number) => {
- const { totalSupply: raw } = await token.call('totalSupply', {})
- const totalSupply = uint256.uint256ToBN(raw)
- expect(totalSupply).to.deep.equal(num.toBigInt(expected))
-}
-
-export const shouldBehaveLikeStarkGateERC20 = (beforeFn: BeforeFn) => {
- describe('StarkGate.ERC20 behavior', function () {
- this.timeout(TIMEOUT)
-
- let t: TestData
-
- before(async () => {
- t = await beforeFn()
- })
-
- it(`should 'permissionedMint' successfully (2x)`, async () => {
- const { alice, bob } = addresses(t)
-
- await t.owner.invoke(t.token, 'permissionedMint', {
- account: alice,
- amount: uint256.bnToUint256(15),
- })
-
- await expectERC20Balance(t.token, t.alice, 15)
-
- await t.owner.invoke(t.token, 'permissionedMint', {
- account: bob,
- amount: uint256.bnToUint256(12),
- })
-
- await expectERC20TotalSupply(t.token, 27)
- await expectERC20Balance(t.token, t.bob, 12)
- })
-
- it(`should 'permissionedBurn' successfully (2x)`, async () => {
- const { alice, bob } = addresses(t)
-
- await t.owner.invoke(t.token, 'permissionedBurn', {
- account: alice,
- amount: uint256.bnToUint256(3),
- })
-
- await expectERC20TotalSupply(t.token, 24)
- await expectERC20Balance(t.token, t.alice, 12)
-
- await t.owner.invoke(t.token, 'permissionedBurn', {
- account: bob,
- amount: uint256.bnToUint256(10),
- })
-
- await expectERC20TotalSupply(t.token, 14)
- await expectERC20Balance(t.token, t.bob, 2)
- })
-
- it(`reverts on 'permissionedBurn' (amount > balance)`, async () => {
- const { alice, bob } = addresses(t)
-
- await expectInvokeError(
- t.owner.invoke(t.token, 'permissionedBurn', {
- account: bob,
- amount: uint256.bnToUint256(103),
- }),
- )
-
- await expectInvokeError(
- t.owner.invoke(t.token, 'permissionedBurn', {
- account: alice,
- amount: uint256.bnToUint256(189),
- }),
- )
- })
-
- it(`reverts on 'permissionedBurn' without permission`, async () => {
- const { alice, bob } = addresses(t)
-
- await expectInvokeError(
- t.alice.invoke(t.token, 'permissionedBurn', {
- account: bob,
- amount: uint256.bnToUint256(103),
- }),
- )
-
- await expectInvokeError(
- t.bob.invoke(t.token, 'permissionedBurn', {
- account: alice,
- amount: uint256.bnToUint256(189),
- }),
- )
- })
-
- it(`should 'permissionedMint' and 'transfer' successfully`, async () => {
- const { alice, bob } = addresses(t)
-
- await t.owner.invoke(t.token, 'permissionedMint', {
- account: bob,
- amount: uint256.bnToUint256(3),
- })
- await t.alice.invoke(t.token, 'transfer', {
- recipient: bob,
- amount: uint256.bnToUint256(3),
- })
-
- await expectERC20Balance(t.token, t.alice, 9)
- await expectERC20Balance(t.token, t.bob, 8)
-
- await t.bob.invoke(t.token, 'transfer', {
- recipient: alice,
- amount: uint256.bnToUint256(4),
- })
-
- await expectERC20Balance(t.token, t.alice, 13)
- await expectERC20Balance(t.token, t.bob, 4)
- })
-
- it(`reverts on 'transfer' (amount > balance)`, async () => {
- const { alice, bob } = addresses(t)
-
- await expectInvokeError(
- t.bob.invoke(t.token, 'transfer', {
- recipient: alice,
- amount: uint256.bnToUint256(12),
- }),
- 'ERC20: transfer amount exceeds balance',
- )
-
- await expectInvokeError(
- t.alice.invoke(t.token, 'transfer', {
- recipient: bob,
- amount: uint256.bnToUint256(17),
- }),
- 'ERC20: transfer amount exceeds balance',
- )
- })
-
- it(`should 'increaseAllowance' and 'transferFrom' successfully - #1`, async () => {
- const { owner, alice, bob } = addresses(t)
-
- await t.bob.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(7),
- })
- await t.alice.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(7),
- })
-
- await t.owner.invoke(t.token, 'transferFrom', {
- sender: alice,
- recipient: bob,
- amount: uint256.bnToUint256(3),
- })
-
- await expectERC20Balance(t.token, t.alice, 10)
- await expectERC20Balance(t.token, t.bob, 7)
-
- await t.owner.invoke(t.token, 'transferFrom', {
- sender: bob,
- recipient: alice,
- amount: uint256.bnToUint256(4),
- })
-
- await expectERC20Balance(t.token, t.alice, 14)
- await expectERC20Balance(t.token, t.bob, 3)
- })
-
- it(`should 'increaseAllowance' and 'transferFrom' successfully - #2`, async () => {
- const { owner, alice, bob } = addresses(t)
-
- await t.bob.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(7),
- })
- await t.alice.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(7),
- })
-
- await t.owner.invoke(t.token, 'transferFrom', {
- sender: alice,
- recipient: bob,
- amount: uint256.bnToUint256(3),
- })
-
- await expectERC20Balance(t.token, t.alice, 11)
- await expectERC20Balance(t.token, t.bob, 6)
-
- await t.bob.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(15),
- })
- await t.alice.invoke(t.token, 'increaseAllowance', {
- spender: owner,
- added_value: uint256.bnToUint256(15),
- })
-
- await t.owner.invoke(t.token, 'transferFrom', {
- sender: alice,
- recipient: bob,
- amount: uint256.bnToUint256(11),
- })
-
- await expectERC20Balance(t.token, t.alice, 0)
- await expectERC20Balance(t.token, t.bob, 17)
- })
-
- it(`should 'decreaseAllowance' and 'transferFrom' successfully`, async () => {
- const { owner, alice, bob } = addresses(t)
-
- await t.bob.invoke(t.token, 'decreaseAllowance', {
- spender: owner,
- subtracted_value: uint256.bnToUint256(10),
- })
-
- await t.owner.invoke(t.token, 'transferFrom', {
- sender: bob,
- recipient: alice,
- amount: uint256.bnToUint256(1),
- })
-
- await expectERC20Balance(t.token, t.alice, 1)
- await expectERC20Balance(t.token, t.bob, 16)
- })
-
- it(`reverts on 'transferFrom' (amount > allowance)`, async () => {
- const { alice, bob } = addresses(t)
-
- await expectInvokeError(
- t.owner.invoke(t.token, 'transferFrom', {
- sender: bob,
- recipient: alice,
- amount: { low: 8n, high: 10n },
- }),
- 'ERC20: insufficient allowance',
- )
-
- await expectInvokeError(
- t.owner.invoke(t.token, 'transferFrom', {
- sender: alice,
- recipient: bob,
- amount: uint256.bnToUint256(208),
- }),
- 'ERC20: insufficient allowance',
- )
- })
- })
-}
diff --git a/contracts/test/token/starkgate/link_token.test.ts b/contracts/test/token/starkgate/link_token.test.ts
deleted file mode 100644
index f33527a..0000000
--- a/contracts/test/token/starkgate/link_token.test.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { account } from '@pluginv3.0/starknet'
-import { starknet } from 'hardhat'
-import { TIMEOUT } from '../../constants'
-import { shouldBehaveLikeStarkGateERC20 } from './behavior/ERC20'
-
-describe('link_token', function () {
- this.timeout(TIMEOUT)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- shouldBehaveLikeStarkGateERC20(async () => {
- const owner = await starknet.OpenZeppelinAccount.createAccount()
- const alice = await starknet.OpenZeppelinAccount.createAccount()
- const bob = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([
- { account: owner.address, amount: 1e21 },
- { account: alice.address, amount: 1e21 },
- { account: bob.address, amount: 1e21 },
- ])
- await owner.deployAccount()
- await alice.deployAccount()
- await bob.deployAccount()
-
- const tokenFactory = await starknet.getContractFactory('link_token')
- await owner.declare(tokenFactory)
- const token = await owner.deploy(tokenFactory, { owner: owner.starknetContract.address })
- return { token, owner, alice, bob }
- })
-})
diff --git a/contracts/test/utils.ts b/contracts/test/utils.ts
new file mode 100644
index 0000000..5a37b12
--- /dev/null
+++ b/contracts/test/utils.ts
@@ -0,0 +1,78 @@
+import { STARKNET_DEVNET_URL } from './constants'
+import { execSync } from 'node:child_process'
+import { Account } from 'starknet'
+import * as path from 'node:path'
+import { ethers } from 'hardhat'
+import { json } from 'starknet'
+import * as fs from 'node:fs'
+
+export type FetchStarknetAccountParams = Readonly<{
+ accountIndex?: number
+}>
+
+export const fetchStarknetAccount = async (params?: FetchStarknetAccountParams) => {
+ const response = await fetch(`${STARKNET_DEVNET_URL}/predeployed_accounts`)
+ const accounts = await response.json()
+ const accIndex = params?.accountIndex ?? 0
+
+ const account = accounts.at(accIndex)
+ if (account == null) {
+ throw new Error(`no account available at index ${accIndex}`)
+ }
+
+ return new Account(
+ {
+ nodeUrl: STARKNET_DEVNET_URL,
+ },
+ account.address,
+ account.private_key,
+ )
+}
+
+export const getStarknetContractArtifacts = (name: string) => {
+ const rootDir = getRootDir()
+ return {
+ contract: getStarknetContractArtifactPath(rootDir, name, false),
+ casm: getStarknetContractArtifactPath(rootDir, name, true),
+ }
+}
+
+export const waitForTransaction = async (
+ tx: () => ReturnType,
+) => {
+ const result = await tx()
+ return await result.wait()
+}
+
+export const waitForTransactions = async (
+ txs: (() => ReturnType)[],
+ cb?: () => void | Promise,
+) => {
+ const results = new Array>>()
+ for (const tx of txs) {
+ results.push(await waitForTransaction(tx))
+ cb != null && (await cb())
+ }
+ return results
+}
+
+const getRootDir = () => {
+ const result = execSync('git rev-parse --show-toplevel').toString()
+ return result.replace(/\n/g, '')
+}
+
+const getStarknetContractArtifactPath = (rootDir: string, name: string, casm: boolean) => {
+ return json.parse(
+ fs
+ .readFileSync(
+ path.join(
+ rootDir,
+ 'contracts',
+ 'target',
+ 'release',
+ `plugin_${name}.${casm ? 'compiled_' : ''}contract_class.json`,
+ ),
+ )
+ .toString('ascii'),
+ )
+}
diff --git a/contracts/vendor/starkware-libs/README.md b/contracts/vendor/starkware-libs/README.md
index 1367c1a..a3cf938 100644
--- a/contracts/vendor/starkware-libs/README.md
+++ b/contracts/vendor/starkware-libs/README.md
@@ -1,6 +1,4 @@
# starkware-libs vendor contracts
-Here we duplicate the `starkware-libs/starkgate-contracts` project as we couldn't find a way to properly import it via NPM (only a few .cairo contracts packaged), PyPI (N/A), or a submodule (complex build).
-
-- `starkware-libs/starkgate-contracts` - duplicate of the original repo at [c08863a](https://github.com/starkware-libs/starkgate-contracts/commit/c08863a1f08226c09f1d0748124192e848d73db9) (includes only the files we use)
-- `starkware-libs/starkgate-contracts-solidity-v0.8` - fork of the original repo at [c08863a](https://github.com/starkware-libs/starkgate-contracts/commit/c08863a1f08226c09f1d0748124192e848d73db9) which loosens the `pragma` declaration for a few interfaces to support v0.8 (includes only the files we use)
+- `starkware-libs/starkgate-contracts` - fork of the original repo at [c08863a](https://github.com/starkware-libs/starkgate-contracts/commit/c08863a1f08226c09f1d0748124192e848d73db9) includes only `std_contracts/ERC20/permitted.cairo`
+- `starkware-libs/cairo-lang` fork of the original repo at [v0.11.0.2](https://github.com/starkware-libs/cairo-lang/tree/v0.11.0.2/src/starkware/starknet) which loosens the `pragma` declaration for a few interfaces to support v0.8 (includes only the files we use)
\ No newline at end of file
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessaging.sol b/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessaging.sol
deleted file mode 100644
index d9b9d28..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessaging.sol
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.8.0;
-
-import "./IStarknetMessagingEvents.sol";
-
-interface IStarknetMessaging is IStarknetMessagingEvents {
- /**
- Sends a message to an L2 contract.
- This function is payable, the payed amount is the message fee.
-
- Returns the hash of the message and the nonce of the message.
- */
- function sendMessageToL2(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload
- ) external payable returns (bytes32, uint256);
-
- /**
- Consumes a message that was sent from an L2 contract.
-
- Returns the hash of the message.
- */
- function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload)
- external
- returns (bytes32);
-
- /**
- Starts the cancellation of an L1 to L2 message.
- A message can be canceled messageCancellationDelay() seconds after this function is called.
-
- Note: This function may only be called for a message that is currently pending and the caller
- must be the sender of the that message.
- */
- function startL1ToL2MessageCancellation(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external returns (bytes32);
-
- /**
- Cancels an L1 to L2 message, this function should be called messageCancellationDelay() seconds
- after the call to startL1ToL2MessageCancellation().
-
- Note that the message fee is not refunded.
- */
- function cancelL1ToL2Message(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external returns (bytes32);
-}
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol b/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol
deleted file mode 100644
index 2f52bfe..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts-solidity-v0.8/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.8.0;
-
-interface IStarknetMessagingEvents {
- // This event needs to be compatible with the one defined in Output.sol.
- event LogMessageToL1(uint256 indexed fromAddress, address indexed toAddress, uint256[] payload);
-
- // An event that is raised when a message is sent from L1 to L2.
- event LogMessageToL2(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce,
- uint256 fee
- );
-
- // An event that is raised when a message from L2 to L1 is consumed.
- event ConsumedMessageToL1(
- uint256 indexed fromAddress,
- address indexed toAddress,
- uint256[] payload
- );
-
- // An event that is raised when a message from L1 to L2 is consumed.
- event ConsumedMessageToL2(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-
- // An event that is raised when a message from L1 to L2 Cancellation is started.
- event MessageToL2CancellationStarted(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-
- // An event that is raised when a message from L1 to L2 is canceled.
- event MessageToL2Canceled(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-}
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/solidity/libraries/NamedStorage.sol b/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/solidity/libraries/NamedStorage.sol
deleted file mode 100644
index 817b793..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/solidity/libraries/NamedStorage.sol
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.6.12;
-
-/*
- Library to provide basic storage, in storage location out of the low linear address space.
- New types of storage variables should be added here upon need.
-*/
-library NamedStorage {
- function bytes32ToUint256Mapping(string memory tag_)
- internal
- pure
- returns (mapping(bytes32 => uint256) storage randomVariable)
- {
- bytes32 location = keccak256(abi.encodePacked(tag_));
- assembly {
- randomVariable_slot := location
- }
- }
-
- function bytes32ToAddressMapping(string memory tag_)
- internal
- pure
- returns (mapping(bytes32 => address) storage randomVariable)
- {
- bytes32 location = keccak256(abi.encodePacked(tag_));
- assembly {
- randomVariable_slot := location
- }
- }
-
- function addressToBoolMapping(string memory tag_)
- internal
- pure
- returns (mapping(address => bool) storage randomVariable)
- {
- bytes32 location = keccak256(abi.encodePacked(tag_));
- assembly {
- randomVariable_slot := location
- }
- }
-
- function getUintValue(string memory tag_) internal view returns (uint256 retVal) {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- retVal := sload(slot)
- }
- }
-
- function setUintValue(string memory tag_, uint256 value) internal {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- sstore(slot, value)
- }
- }
-
- function setUintValueOnce(string memory tag_, uint256 value) internal {
- require(getUintValue(tag_) == 0, "ALREADY_SET");
- setUintValue(tag_, value);
- }
-
- function getAddressValue(string memory tag_) internal view returns (address retVal) {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- retVal := sload(slot)
- }
- }
-
- function setAddressValue(string memory tag_, address value) internal {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- sstore(slot, value)
- }
- }
-
- function setAddressValueOnce(string memory tag_, address value) internal {
- require(getAddressValue(tag_) == address(0x0), "ALREADY_SET");
- setAddressValue(tag_, value);
- }
-
- function getBoolValue(string memory tag_) internal view returns (bool retVal) {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- retVal := sload(slot)
- }
- }
-
- function setBoolValue(string memory tag_, bool value) internal {
- bytes32 slot = keccak256(abi.encodePacked(tag_));
- assembly {
- sstore(slot, value)
- }
- }
-}
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessaging.sol b/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessaging.sol
deleted file mode 100644
index 5388ac6..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessaging.sol
+++ /dev/null
@@ -1,54 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.6.12;
-
-import "./IStarknetMessagingEvents.sol";
-
-interface IStarknetMessaging is IStarknetMessagingEvents {
- /**
- Sends a message to an L2 contract.
- This function is payable, the payed amount is the message fee.
-
- Returns the hash of the message and the nonce of the message.
- */
- function sendMessageToL2(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload
- ) external payable returns (bytes32, uint256);
-
- /**
- Consumes a message that was sent from an L2 contract.
-
- Returns the hash of the message.
- */
- function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload)
- external
- returns (bytes32);
-
- /**
- Starts the cancellation of an L1 to L2 message.
- A message can be canceled messageCancellationDelay() seconds after this function is called.
-
- Note: This function may only be called for a message that is currently pending and the caller
- must be the sender of the that message.
- */
- function startL1ToL2MessageCancellation(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external returns (bytes32);
-
- /**
- Cancels an L1 to L2 message, this function should be called messageCancellationDelay() seconds
- after the call to startL1ToL2MessageCancellation().
-
- Note that the message fee is not refunded.
- */
- function cancelL1ToL2Message(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external returns (bytes32);
-}
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol b/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol
deleted file mode 100644
index 9e7c841..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/IStarknetMessagingEvents.sol
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.6.12;
-
-interface IStarknetMessagingEvents {
- // This event needs to be compatible with the one defined in Output.sol.
- event LogMessageToL1(uint256 indexed fromAddress, address indexed toAddress, uint256[] payload);
-
- // An event that is raised when a message is sent from L1 to L2.
- event LogMessageToL2(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce,
- uint256 fee
- );
-
- // An event that is raised when a message from L2 to L1 is consumed.
- event ConsumedMessageToL1(
- uint256 indexed fromAddress,
- address indexed toAddress,
- uint256[] payload
- );
-
- // An event that is raised when a message from L1 to L2 is consumed.
- event ConsumedMessageToL2(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-
- // An event that is raised when a message from L1 to L2 Cancellation is started.
- event MessageToL2CancellationStarted(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-
- // An event that is raised when a message from L1 to L2 is canceled.
- event MessageToL2Canceled(
- address indexed fromAddress,
- uint256 indexed toAddress,
- uint256 indexed selector,
- uint256[] payload,
- uint256 nonce
- );
-}
diff --git a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/StarknetMessaging.sol b/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/StarknetMessaging.sol
deleted file mode 100644
index 8b2d68d..0000000
--- a/contracts/vendor/starkware-libs/starkgate-contracts/src/starkware/starknet/solidity/StarknetMessaging.sol
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0.
-pragma solidity ^0.6.12;
-
-import "./IStarknetMessaging.sol";
-import "../../solidity/libraries/NamedStorage.sol";
-
-/**
- Implements sending messages to L2 by adding them to a pipe and consuming messages from L2 by
- removing them from a different pipe. A deriving contract can handle the former pipe and add items
- to the latter pipe while interacting with L2.
-*/
-contract StarknetMessaging is IStarknetMessaging {
- /*
- Random slot storage elements and accessors.
- */
- string constant L1L2_MESSAGE_MAP_TAG = "STARKNET_1.0_MSGING_L1TOL2_MAPPPING_V2";
- string constant L2L1_MESSAGE_MAP_TAG = "STARKNET_1.0_MSGING_L2TOL1_MAPPPING";
-
- string constant L1L2_MESSAGE_NONCE_TAG = "STARKNET_1.0_MSGING_L1TOL2_NONCE";
-
- string constant L1L2_MESSAGE_CANCELLATION_MAP_TAG = (
- "STARKNET_1.0_MSGING_L1TOL2_CANCELLATION_MAPPPING"
- );
-
- string constant L1L2_MESSAGE_CANCELLATION_DELAY_TAG = (
- "STARKNET_1.0_MSGING_L1TOL2_CANCELLATION_DELAY"
- );
-
- uint256 public constant MAX_L1_MSG_FEE = 1 ether;
-
- /**
- Returns the msg_fee + 1 for the message with the given 'msgHash',
- or 0 if no message with such a hash is pending.
- */
- function l1ToL2Messages(bytes32 msgHash) external view returns (uint256) {
- return l1ToL2Messages()[msgHash];
- }
-
- function l2ToL1Messages(bytes32 msgHash) external view returns (uint256) {
- return l2ToL1Messages()[msgHash];
- }
-
- function l1ToL2Messages() internal pure returns (mapping(bytes32 => uint256) storage) {
- return NamedStorage.bytes32ToUint256Mapping(L1L2_MESSAGE_MAP_TAG);
- }
-
- function l2ToL1Messages() internal pure returns (mapping(bytes32 => uint256) storage) {
- return NamedStorage.bytes32ToUint256Mapping(L2L1_MESSAGE_MAP_TAG);
- }
-
- function l1ToL2MessageNonce() public view returns (uint256) {
- return NamedStorage.getUintValue(L1L2_MESSAGE_NONCE_TAG);
- }
-
- function messageCancellationDelay() public view returns (uint256) {
- return NamedStorage.getUintValue(L1L2_MESSAGE_CANCELLATION_DELAY_TAG);
- }
-
- function messageCancellationDelay(uint256 delayInSeconds) internal {
- NamedStorage.setUintValue(L1L2_MESSAGE_CANCELLATION_DELAY_TAG, delayInSeconds);
- }
-
- /**
- Returns the timestamp at the time cancelL1ToL2Message was called with a message
- matching 'msgHash'.
-
- The function returns 0 if cancelL1ToL2Message was never called.
- */
- function l1ToL2MessageCancellations(bytes32 msgHash) external view returns (uint256) {
- return l1ToL2MessageCancellations()[msgHash];
- }
-
- function l1ToL2MessageCancellations()
- internal
- pure
- returns (mapping(bytes32 => uint256) storage)
- {
- return NamedStorage.bytes32ToUint256Mapping(L1L2_MESSAGE_CANCELLATION_MAP_TAG);
- }
-
- /**
- Returns the hash of an L1 -> L2 message from msg.sender.
- */
- function getL1ToL2MsgHash(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) internal view returns (bytes32) {
- return
- keccak256(
- abi.encodePacked(
- uint256(msg.sender),
- toAddress,
- nonce,
- selector,
- payload.length,
- payload
- )
- );
- }
-
- /**
- Sends a message to an L2 contract.
- */
- function sendMessageToL2(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload
- ) external payable override returns (bytes32, uint256) {
- require(msg.value <= MAX_L1_MSG_FEE, "MAX_L1_MSG_FEE_EXCEEDED");
- uint256 nonce = l1ToL2MessageNonce();
- NamedStorage.setUintValue(L1L2_MESSAGE_NONCE_TAG, nonce + 1);
- emit LogMessageToL2(msg.sender, toAddress, selector, payload, nonce, msg.value);
- bytes32 msgHash = getL1ToL2MsgHash(toAddress, selector, payload, nonce);
- // Note that the inclusion of the unique nonce in the message hash implies that
- // l1ToL2Messages()[msgHash] was not accessed before.
- l1ToL2Messages()[msgHash] = msg.value + 1;
- return (msgHash, nonce);
- }
-
- /**
- Consumes a message that was sent from an L2 contract.
-
- Returns the hash of the message.
- */
- function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload)
- external
- override
- returns (bytes32)
- {
- bytes32 msgHash = keccak256(
- abi.encodePacked(fromAddress, uint256(msg.sender), payload.length, payload)
- );
-
- require(l2ToL1Messages()[msgHash] > 0, "INVALID_MESSAGE_TO_CONSUME");
- emit ConsumedMessageToL1(fromAddress, msg.sender, payload);
- l2ToL1Messages()[msgHash] -= 1;
- return msgHash;
- }
-
- function startL1ToL2MessageCancellation(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external override returns (bytes32) {
- emit MessageToL2CancellationStarted(msg.sender, toAddress, selector, payload, nonce);
- bytes32 msgHash = getL1ToL2MsgHash(toAddress, selector, payload, nonce);
- uint256 msgFeePlusOne = l1ToL2Messages()[msgHash];
- require(msgFeePlusOne > 0, "NO_MESSAGE_TO_CANCEL");
- l1ToL2MessageCancellations()[msgHash] = block.timestamp;
- return msgHash;
- }
-
- function cancelL1ToL2Message(
- uint256 toAddress,
- uint256 selector,
- uint256[] calldata payload,
- uint256 nonce
- ) external override returns (bytes32) {
- emit MessageToL2Canceled(msg.sender, toAddress, selector, payload, nonce);
- bytes32 msgHash = getL1ToL2MsgHash(toAddress, selector, payload, nonce);
- uint256 msgFeePlusOne = l1ToL2Messages()[msgHash];
- require(msgFeePlusOne != 0, "NO_MESSAGE_TO_CANCEL");
-
- uint256 requestTime = l1ToL2MessageCancellations()[msgHash];
- require(requestTime != 0, "MESSAGE_CANCELLATION_NOT_REQUESTED");
-
- uint256 cancelAllowedTime = requestTime + messageCancellationDelay();
- require(cancelAllowedTime >= requestTime, "CANCEL_ALLOWED_TIME_OVERFLOW");
- require(block.timestamp >= cancelAllowedTime, "MESSAGE_CANCELLATION_NOT_ALLOWED_YET");
-
- l1ToL2Messages()[msgHash] = 0;
- return (msgHash);
- }
-}
-
diff --git a/docs/artifacts.md b/docs/artifacts.md
new file mode 100644
index 0000000..216a336
--- /dev/null
+++ b/docs/artifacts.md
@@ -0,0 +1,19 @@
+# Artifacts
+
+## A Note on Starknet Artifacts
+
+In `starknet.js` v6.7.0, it is necessary to supply both the sierra and sierra casm compilation outputs to a declare transaction as shown [here](https://www.starknetjs.com/docs/next/guides/create_contract#declare-for-a-new-class).
+
+The [`declare`](https://github.com/starknet-io/starknet.js/blob/a85d48ee73acb1365da6bef3f9d3a65153f9a422/src/account/default.ts#L393) method uses the [`artifact` field to compute the `class_hash`](https://github.com/starknet-io/starknet.js/blob/a85d48ee73acb1365da6bef3f9d3a65153f9a422/src/utils/contract.ts#L38), and the [`casm` field to compute the `compiled_class_hash`](https://github.com/starknet-io/starknet.js/blob/a85d48ee73acb1365da6bef3f9d3a65153f9a422/src/utils/contract.ts#L30).
+
+For V2 and V3 declare transactions, both the `class_hash` and `compiled_class_hash` are required to construct the tx hash:
+
+- [V3 declare transaction docs](https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/transactions/#v3_hash_calculation_2)
+- [V2 declare transaction docs](https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/transactions/#v2_deprecated_hash_calculation)
+ - Side note: even though V2 is deprecated, I'm still including it bc [`starknet.js` defaults to transaction version 2 for backwards compatibility in v6.7.0](https://github.com/starknet-io/starknet.js/blob/a85d48ee73acb1365da6bef3f9d3a65153f9a422/src/account/default.ts#L75)
+
+If you attempt to pass only the casm artifact alone or the sierra artifact alone, this causes an error like the one below:
+
+```sh
+"Extract compiledClassHash failed, provide (CairoAssembly).casm file or compiledClassHash"
+```
diff --git a/docs/emergency-protocol/README.md b/docs/emergency-protocol/README.md
index 94a784f..82b6150 100644
--- a/docs/emergency-protocol/README.md
+++ b/docs/emergency-protocol/README.md
@@ -4,7 +4,7 @@
Today Plugin price feeds are used by many DeFi protocols to secure billions of dollars. Whilst feeds report fresh prices the majority of the time, L2 feeds will report stale price data whenever the L2 chain stops producing new blocks. This can happen whenever the L2 Sequencer fails to process any new transactions. Whenever this happens, an arbitrage opportunity is created for malicious actors to take advantage of the price difference between the price inside and outside the L2 chain.
-The Starknet Emergency Protocol provides a way for Plugin price feed consumers to guard against the scenario described above. The protocol tracks the last known health of the Sequencer and reports it's health on chain along with the timestamp of when it either comes back online or goes offline. This allows consuming contracts to implement a grace period in their contracts to revert transactions whenever the Sequencer is down.
+The Starknet Emergency Protocol provides a way for Plugin price feed consumers to guard against the scenario described above. The protocol tracks the last known health of the Sequencer and reports its health on chain along with the timestamp of when it either comes back online or goes offline. This allows consuming contracts to implement a grace period in their contracts to revert transactions whenever the Sequencer is down.
For more background information check the [official docs.](https://docs.chain.link/docs/l2-sequencer-flag/)
@@ -23,7 +23,7 @@ The diagram above illustrates the general path of how the Sequencer’s status i
### Contracts
- L1 Ethereum (Solditiy):
- - [StarknetValidator.sol](https://github.com/goplugin/plugin-starknet/blob/develop/contracts/src/plugin/solidity/emergency/StarknetValidator.sol)
+ - [StarknetValidator.sol](https://github.com/goplugin/plugin-starknet/blob/develop/contracts/solidity/emergency/StarknetValidator.sol)
- L2 Starknet (Cairo):
- [SequencerUptimeFeed.cairo](https://github.com/goplugin/plugin-starknet/blob/develop/contracts/src/plugin/cairo/emergency/SequencerUptimeFeed/sequencer_uptime_feed.cairo)
@@ -73,34 +73,53 @@ In the event that the Sequencer is down, messages will not be transmitted from L
### Bridge Fees
-As of version v0.10.0, Starknet has begun introducing fees to send messages from L1 to L2. These fees are used to pay for the transaction
-on L2. This has been done so that the Sequencer has an incentive to process L2 messags. Whilst today `v0.10.0` still processes messages sent
-with `msg.value = 0`, Starknet has plans to charge a non 0 fee in the upcoming release. As the Emergency Protocol needs to send messages cross chain,
+As of writing, on version v0.11.0, Starknet has begun charging mandatory fees to send messages from L1 to L2. These fees are used to pay for the transaction
+on L2. As the Emergency Protocol needs to send messages cross chain,
the protocol needs a way to estimate gas fees. Currently, the `StarkwareValidator` contract on L1 does the following to estimate the amount of required
gas.
-1. Estimate gas fees by running the command below. The command is from Starkware's standard CLI.
+1. Estimate gas fees by running the command below. The command is from Starkware's standard CLI (using version 0.11.0.x)
```
starknet estimate_message_fee \
- --feeder_gateway_url=https://alpha4.starknet.io/feeder_gateway/ \
- --abi=contracts/starknet-artifacts/src/plugin/cairo/emergency/SequencerUptimeFeed/sequencer_uptime_feed.cairo/sequencer_uptime_feed.json \
- --from_address ${FROM} \
- --address ${TO} \
+ --feeder_gateway_url=https://alpha4.starknet.io/feeder_gateway/
+ --from_address ${L1_SENDER_ADDR} \
+ --address ${UPTIME_FEED_ADDR} \
--function update_status \
--inputs ${STATUS} ${TIMESTAMP}
```
-In order to reliably ensure that cross chain messages are sent with sufficient gas, the estimate is multiplied by a buffer. This buffer
-is arbitrarily chosen depending on what the Ops team determines to be a sufficient buffer.
+Make sure that the `L1_SENDER_ADDR` is equal to the l1 sender storage variable on the uptime feed, or else the gateway will respond with a revert instead of the values. If you don't set the l1 sender storage variable, it'll be 0 by default (as in the example below)
+
+Example Query and response:
+
+```
+starknet estimate_message_fee \
+ --feeder_gateway_url=https://alpha4.starknet.io/feeder_gateway/ \
+ --from_address 0x0 \
+ --address=0x06f4279f832de1afd94ab79aa1766628d2c1e70bc7f74bfba3335db8e728a7e6 \
+ --function update_status \
+ --inputs 0x1 123123
+
+The estimated fee is: 3739595758116898 WEI (0.003740 ETH).
+Gas usage: 17266
+Gas price: 216587267353 WEI
+```
+
+In order to reliably ensure that cross chain messages are sent with sufficient gas, the estimate is multiplied by a buffer. At the time of writing (Starknet v.0.11.0), Starkware has told us that L2 gas prices are equal to L1 gas prices and are denominated in Ethereum Wei, so we use L1 gas price feed to get the gas price:
-2. Read the current L1 gas price from Plugin's L1 gas price feed
-3. Estimate gas as the product of the steps above.
+1. Read the current L1 gas price from Plugin's L1 gas price feed
+2. Multiply gas price by a buffer
+3. Multiply product of above by the number of gas units
```solidity
-gasFee = gasUnitsIncludingBuffer * l1GasPrice
+gasFee = buffer * l1GasPrice * numGasUnits
```
+The gas units that it costs is also derived from the starknet estimate_message_fee command (as shown above).
+
+As of the time of writing (Starknet v. 0.11.0), we recommend a gasAdjustment of 130 (or 1.3x buffer) and a gas units to be 17300.
+
### Layer2 Sequencer Health External Adapter
[Code](https://github.com/goplugin/external-adapters-js/tree/develop/packages/sources/layer2-sequencer-health)
diff --git a/docs/integration-tests/README.md b/docs/integration-tests/README.md
index cfb01ae..b78b0ab 100644
--- a/docs/integration-tests/README.md
+++ b/docs/integration-tests/README.md
@@ -78,21 +78,20 @@ and [here](../../integration-tests/soak/soak_runner_test.go)
Here you will find pod logs for all the plugin nodes as well as Devnet / Geth
-
# Testing wiki
## Testnet
- Chain name - `Starknet`
-- Chain ID - `SN_GOERLI`
- - Testnet 1 - `[https://alpha4.starknet.io](https://alpha4.starknet.io)`
- - Testnet 2 - [`https://alpha4-2.starknet.io`](https://alpha4-2.starknet.io/)
+- Chain ID - `SN_SEPOLIA`
+ - Testnet 1 - `[https://alpha4.starknet.io](https://alpha4.starknet.io)`
+ - Testnet 2 - [`https://alpha4-2.starknet.io`](https://alpha4-2.starknet.io/)
## Mainnet
- Chain name - `Starknet`
- Chain ID - `SN_MAIN`
- - `[https://alpha-mainnet.starknet.io](https://alpha-mainnet.starknet.io)`
+ - `[https://alpha-mainnet.starknet.io](https://alpha-mainnet.starknet.io)`
# Node config
@@ -123,6 +122,15 @@ ListenAddresses = ['0.0.0.0:6690']
NODE_URL=
ACCOUNT=
PRIVATE_KEY=
+PLUGIN_ENV_USER=John;
+PLUGIN_IMAGE={AWS_OIDC}.dkr.ecr.{AWS_REGION}.amazonaws.com/plugin;
+PLUGIN_VERSION=develop;
+INTERNAL_DOCKER_REPO={AWS_OIDC}.dkr.ecr.{AWS_REGION}.amazonaws.com; # required for mock adapter
+L2_RPC_URL=https://alpha4.starknet.io; # testnet only
+NODE_COUNT=5;
+TEST_DURATION=70h; # for soak
+TEST_USE_ENV_VAR_CONFIG=true; # for soak
+TTL=72h # for soak
```
1. Deploy link
@@ -168,74 +176,74 @@ yarn gauntlet ocr2:set_billing --observationPaymentGjuels= --transmission
```
8. Set config
- 1. Example config testnet
-
- ```bash
- {
- "f": 1,
- "signers": [
- "ocr2on_starknet_0371028377bfd793b7e2965757e348309e7242802d20253da6ab81c8eb4b4051",
- "ocr2on_starknet_073cadfc4474e8c6c79f66fa609da1dbcd5be4299ff9b1f71646206d1faca1fc",
- "ocr2on_starknet_0386d1a9d93792c426739f73afa1d0b19782fbf30ae27ce33c9fbd4da659cd80",
- "ocr2on_starknet_005360052758819ba2af790469a28353b7ff6f8b84176064ab572f6cc20e5fb4"
- ],
- "transmitters": [
- "0x0...",
- "0x0...",
- "0x0...",
- "0x0..."
- ],
- "onchainConfig": "",
- "offchainConfig": {
- "deltaProgressNanoseconds": 8000000000,
- "deltaResendNanoseconds": 30000000000,
- "deltaRoundNanoseconds": 3000000000,
- "deltaGraceNanoseconds": 1000000000,
- "deltaStageNanoseconds": 20000000000,
- "rMax": 5,
- "s": [
- 1,
- 1,
- 1,
- 1
- ],
- "offchainPublicKeys": [
- "ocr2off_starknet_0...",
- "ocr2off_starknet_0...",
- "ocr2off_starknet_0...",
- "ocr2off_starknet_0..."
- ],
- "peerIds": [
- "12D3..",
- "12D3..",
- "12D3..",
- "12D3.."
- ],
- "reportingPluginConfig": {
- "alphaReportInfinite": false,
- "alphaReportPpb": 0,
- "alphaAcceptInfinite": false,
- "alphaAcceptPpb": 0,
- "deltaCNanoseconds": 1000000000
- },
- "maxDurationQueryNanoseconds": 0,
- "maxDurationObservationNanoseconds": 1000000000,
- "maxDurationReportNanoseconds": 2000000000,
- "maxDurationShouldAcceptFinalizedReportNanoseconds": 2000000000,
- "maxDurationShouldTransmitAcceptedReportNanoseconds": 2000000000,
- "configPublicKeys": [
- "ocr2cfg_starknet_...",
- "ocr2cfg_starknet_...",
- "ocr2cfg_starknet_...",
- "ocr2cfg_starknet_..."
- ]
- },
- "offchainConfigVersion": 2,
- "secret": "some secret you want"
- }
- ```
+ 1. Example config testnet
+
+ ```bash
+ {
+ "f": 1,
+ "signers": [
+ "ocr2on_starknet_0371028377bfd793b7e2965757e348309e7242802d20253da6ab81c8eb4b4051",
+ "ocr2on_starknet_073cadfc4474e8c6c79f66fa609da1dbcd5be4299ff9b1f71646206d1faca1fc",
+ "ocr2on_starknet_0386d1a9d93792c426739f73afa1d0b19782fbf30ae27ce33c9fbd4da659cd80",
+ "ocr2on_starknet_005360052758819ba2af790469a28353b7ff6f8b84176064ab572f6cc20e5fb4"
+ ],
+ "transmitters": [
+ "0x0...",
+ "0x0...",
+ "0x0...",
+ "0x0..."
+ ],
+ "onchainConfig": "",
+ "offchainConfig": {
+ "deltaProgressNanoseconds": 8000000000,
+ "deltaResendNanoseconds": 30000000000,
+ "deltaRoundNanoseconds": 3000000000,
+ "deltaGraceNanoseconds": 1000000000,
+ "deltaStageNanoseconds": 20000000000,
+ "rMax": 5,
+ "s": [
+ 1,
+ 1,
+ 1,
+ 1
+ ],
+ "offchainPublicKeys": [
+ "ocr2off_starknet_0...",
+ "ocr2off_starknet_0...",
+ "ocr2off_starknet_0...",
+ "ocr2off_starknet_0..."
+ ],
+ "peerIds": [
+ "12D3..",
+ "12D3..",
+ "12D3..",
+ "12D3.."
+ ],
+ "reportingPluginConfig": {
+ "alphaReportInfinite": false,
+ "alphaReportPpb": 0,
+ "alphaAcceptInfinite": false,
+ "alphaAcceptPpb": 0,
+ "deltaCNanoseconds": 1000000000
+ },
+ "maxDurationQueryNanoseconds": 2000000000,
+ "maxDurationObservationNanoseconds": 1000000000,
+ "maxDurationReportNanoseconds": 2000000000,
+ "maxDurationShouldAcceptFinalizedReportNanoseconds": 2000000000,
+ "maxDurationShouldTransmitAcceptedReportNanoseconds": 2000000000,
+ "configPublicKeys": [
+ "ocr2cfg_starknet_...",
+ "ocr2cfg_starknet_...",
+ "ocr2cfg_starknet_...",
+ "ocr2cfg_starknet_..."
+ ]
+ },
+ "offchainConfigVersion": 2,
+ "secret": "some secret you want"
+ }
+ ```
```bash
yarn gauntlet ocr2:set_config --input=
-```
\ No newline at end of file
+```
diff --git a/docs/integration-tests/on-demand-soak.md b/docs/integration-tests/on-demand-soak.md
new file mode 100644
index 0000000..18e31be
--- /dev/null
+++ b/docs/integration-tests/on-demand-soak.md
@@ -0,0 +1,22 @@
+## On demand soak test
+
+
+Soak tests can be triggered in GHA remotely with custom duration on devnet / testnet
+
+1. Navigate to Actions
+2. Select Integration Tests - Soak
+3. Click run workflow
+4. Enter RPC url (Optional this is for testing on testnet)
+5. Specify node count (default is 4+1)
+6. Specify TTL of the namespace (This is when to destroy the env)
+7. Specify duration of the soak (Should be lower than TTL)
+8. Enter private key L2 (Optional, only for testnet)
+9. Enter account address L2 (Optional, only for testnet)
+
+
+## Monitoring
+Tests will print out a namespace in the "TestOCRSoak" phase in the Run tests step (e.g plugin-ocr-starknet-472d5)
+
+1. Enter the namespace in grafana plugin testing insights dashboard and the logs will be visible
+
+The remote runner contains the test run and outputs.
\ No newline at end of file
diff --git a/examples/contracts/aggregator-consumer/.gitignore b/examples/contracts/aggregator-consumer/.gitignore
deleted file mode 100644
index 793bd7c..0000000
--- a/examples/contracts/aggregator-consumer/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-cache/
-starknet-artifacts/
\ No newline at end of file
diff --git a/examples/contracts/aggregator-consumer/contracts/Aggregator_consumer.cairo b/examples/contracts/aggregator-consumer/contracts/Aggregator_consumer.cairo
deleted file mode 100644
index aae9031..0000000
--- a/examples/contracts/aggregator-consumer/contracts/Aggregator_consumer.cairo
+++ /dev/null
@@ -1,32 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from plugin.cairo.ocr2.IAggregator import IAggregator, Round
-
-@storage_var
-func AggregatorConsumer_ocr_address() -> (address: felt) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(address: felt) {
- AggregatorConsumer_ocr_address.write(address);
- return ();
-}
-
-@view
-func readLatestRound{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- let (address) = AggregatorConsumer_ocr_address.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=address);
- return (round,);
-}
-
-@view
-func readDecimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- decimals: felt
-) {
- let (address) = AggregatorConsumer_ocr_address.read();
- let (decimals) = IAggregator.decimals(contract_address=address);
- return (decimals,);
-}
diff --git a/examples/contracts/aggregator-consumer/contracts/MockAggregator.cairo b/examples/contracts/aggregator-consumer/contracts/MockAggregator.cairo
deleted file mode 100644
index 87b4b36..0000000
--- a/examples/contracts/aggregator-consumer/contracts/MockAggregator.cairo
+++ /dev/null
@@ -1,8 +0,0 @@
-%lang starknet
-
-from plugin.cairo.ocr2.mocks.MockAggregator import (
- constructor,
- set_latest_round_data,
- latest_round_data,
- decimals,
-)
diff --git a/examples/contracts/aggregator-consumer/contracts/Price_Consumer_With_Sequencer_Check.cairo b/examples/contracts/aggregator-consumer/contracts/Price_Consumer_With_Sequencer_Check.cairo
deleted file mode 100644
index e5d9b15..0000000
--- a/examples/contracts/aggregator-consumer/contracts/Price_Consumer_With_Sequencer_Check.cairo
+++ /dev/null
@@ -1,74 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.alloc import alloc
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.math import assert_not_zero
-from starkware.cairo.common.math_cmp import is_nn
-from starkware.cairo.common.bool import TRUE, FALSE
-from starkware.starknet.common.syscalls import get_block_timestamp
-
-from plugin.cairo.ocr2.IAggregator import IAggregator, Round
-
-@storage_var
-func PriceConsumerWithSequencerCheck_uptime_feed_address() -> (address: felt) {
-}
-
-@storage_var
-func PriceConsumerWithSequencerCheck_aggregator_address() -> (address: felt) {
-}
-
-// If the sequencer is up and that 60 sec has passed,
-// The function retrieves the latest price from the data feed using the priceFeed object.
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- uptime_feed_address: felt, aggregator_address: felt
-) {
- assert_not_zero(uptime_feed_address);
- assert_not_zero(aggregator_address);
-
- PriceConsumerWithSequencerCheck_uptime_feed_address.write(uptime_feed_address);
- PriceConsumerWithSequencerCheck_aggregator_address.write(aggregator_address);
- return ();
-}
-
-// If the sequencer is up and report is OK then we can get the latest price.
-@view
-func get_latest_price{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: felt
-) {
- assert_sequencer_healthy();
- let (aggregator_address) = PriceConsumerWithSequencerCheck_aggregator_address.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=aggregator_address);
- return (round=round.answer);
-}
-
-// Errors if the report is stale, or it's reported that Sequencer node is down
-@external
-func assert_sequencer_healthy{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
- alloc_locals;
-
- let (uptime_feed_address) = PriceConsumerWithSequencerCheck_uptime_feed_address.read();
-
- // Get latest_round_data from sequencer contract which should be update by a message send from L1
- let (round: Round) = IAggregator.latest_round_data(contract_address=uptime_feed_address);
- let (local block_timestemp) = get_block_timestamp();
- let time = block_timestemp - round.updated_at;
-
- // After 60 sec the report is considered stale
- let is_ls = is_nn(time - (60 + 1));
-
- // 0 if the sequencer is up and 1 if it is down
- if (round.answer == 0) {
- with_attr error_message("PriceConsumer: L2 Sequencer is up, report stale") {
- assert is_ls = 1;
- }
- return ();
- }
- with_attr error_message("PriceConsumer: L2 Sequencer is down, report stale") {
- assert is_ls = 1;
- }
- with_attr error_message("PriceConsumer: L2 Sequencer is down, report ok") {
- assert round.answer = 0;
- }
- return ();
-}
diff --git a/examples/contracts/aggregator-consumer/getting_start.md b/examples/contracts/aggregator-consumer/getting_start.md
deleted file mode 100644
index 70775c2..0000000
--- a/examples/contracts/aggregator-consumer/getting_start.md
+++ /dev/null
@@ -1,25 +0,0 @@
-0. `.env` contains predeploy and funded account details, such as DEPLOYER_ACCOUNT_ADDRESS and DEPLOYER_PRIVATE_KEY
-
-1. Set up the network `export STARKNET_NETWORK=alpha-goerli`
-
-2. Choose a wallet provider `export STARKNET_WALLET=starkware.starknet.wallets.open_zeppelin.OpenZeppelinAccount`
-
-3. If you don't have an account create it with the command `starknet new_account`
-
-4. Open that link https://faucet.goerli.starknet.io/ and past the address to get some faucet. If you can not get faucet you can transfer some eth from one of you L1 accounts to starknet https://goerli.starkgate.starknet.io/.
-
-5. When you have be able to get some faucet you can deploy your account `starknet deploy_account` (for more information take a look at this documentation https://starknet.io/docs/hello_starknet/account_setup.html).
-
-6. Create a `.env` in `exemples/contracts/aggregator-consumer`and copy past your account address under `DEPLOYER_ACCOUNT_ADDRESS` and you private key under `DEPLOYER_PRIVATE_KEY`. You can find the private key in your home directory under `.starknet_accounts` folder in `starknet_open_zeppelin_accounts.json`.
-
-7. Start by deploying accounts with `npx ts-node ./scripts/deploy_accounts.ts`
-
-8. It'll write in previously created `.env`.
-
-9. Open that link https://faucet.goerli.starknet.io/ and past the address of the new accounts to get some faucet.
-
-10. Deploy the contracts by running `npx ts-node ./scripts/deploy_contracts.ts.`
-
-11. You can now read decimals and latest round data by running `yarn readDecimals` and `yarn readLatestRound`.
-
-12. You can update value and see continuously the data by openning another terminal and run `npx ts-node ./scripts/updateLatestRound.ts` in one terminal and `npx ts-node ./scripts/readContinuously` into another one.
diff --git a/examples/contracts/aggregator-consumer/hardhat.config.ts b/examples/contracts/aggregator-consumer/hardhat.config.ts
deleted file mode 100644
index a954ac9..0000000
--- a/examples/contracts/aggregator-consumer/hardhat.config.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { HardhatUserConfig } from 'hardhat/types'
-import '@shardlabs/starknet-hardhat-plugin'
-import '@nomiclabs/hardhat-ethers'
-
-const config: HardhatUserConfig = {
- solidity: '0.8.14',
- starknet: {
- venv: 'active',
- network: 'devnet',
- wallets: {
- OpenZeppelin: {
- accountName: 'OpenZeppelin',
- modulePath: 'starkware.starknet.wallets.open_zeppelin.OpenZeppelinAccount',
- accountPath: '~/.starknet_accounts',
- },
- },
- },
- networks: {
- devnet: {
- url: 'http://127.0.0.1:5050',
- },
- integratedDevnet: {
- url: 'http://127.0.0.1:5050',
- venv: 'active',
- args: ['--lite-mode'],
- // dockerizedVersion: "0.2.0"
- },
- },
- paths: {
- cairoPaths: ['../../../contracts/src'],
- },
-}
-
-export default config
diff --git a/examples/contracts/aggregator-consumer/package.json b/examples/contracts/aggregator-consumer/package.json
deleted file mode 100644
index 59b0990..0000000
--- a/examples/contracts/aggregator-consumer/package.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "@pluginv3.0/starknet-ocr2-consumer",
- "version": "0.1.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "compile:cairo": "hardhat starknet-compile",
- "compile": "yarn compile:cairo",
- "test": "npx hardhat --network localhost test",
- "readDecimals": "npx ts-node ./scripts/readDecimals.ts",
- "readLatestRound": "npx ts-node ./scripts/readLatestRound.ts"
- },
- "keywords": [],
- "author": "",
- "license": "MIT",
- "devDependencies": {
- "@nomiclabs/hardhat-ethers": "^2.1.0",
- "@shardlabs/starknet-hardhat-plugin": "^0.8.0-alpha.0",
- "@types/chai": "^4.3.3",
- "@types/mocha": "^9.1.1",
- "chai": "^4.3.6",
- "hardhat": "^*"
- },
- "dependencies": {
- "@pluginv3.0/starknet": "^1.0.0",
- "dotenv": "^16.0.1"
- }
-}
diff --git a/examples/contracts/aggregator-consumer/scripts/consumerValidator.ts b/examples/contracts/aggregator-consumer/scripts/consumerValidator.ts
deleted file mode 100644
index 0f2ebaa..0000000
--- a/examples/contracts/aggregator-consumer/scripts/consumerValidator.ts
+++ /dev/null
@@ -1,127 +0,0 @@
-import { ethers, starknet, network } from 'hardhat'
-import { Contract, ContractFactory } from 'ethers'
-import { HttpNetworkConfig } from 'hardhat/types'
-
-import dotenv from 'dotenv'
-import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
-import { deployMockContract, MockContract } from '@ethereum-waffle/mock-contract'
-import { Account, Contract as StarknetContract } from 'starknet'
-import {
- createDeployerAccount,
- loadContractPath,
- loadContract_Solidity,
- loadContract_Solidity_V8,
- makeProvider,
-} from './utils'
-
-dotenv.config({ path: __dirname + '/../.env' })
-const UPTIME_FEED_PATH =
- '../../../../contracts/starknet-artifacts/src/plugin/cairo/emergency/SequencerUptimeFeed'
-const UPTIME_FEED_NAME = 'sequencer_uptime_feed'
-
-let validator: Contract
-let mockStarknetMessengerFactory: ContractFactory
-let mockStarknetMessenger: Contract
-let deployer: SignerWithAddress
-let eoaValidator: SignerWithAddress
-let networkUrl: string
-let account: Account
-
-let mockGasPriceFeed: MockContract
-let mockAccessController: MockContract
-let mockAggregator: MockContract
-
-export async function consumerValidator() {
- const provider = makeProvider()
-
- account = createDeployerAccount(provider)
-
- networkUrl = (network.config as HttpNetworkConfig).url
- const accounts = await ethers.getSigners()
- deployer = accounts[0]
- eoaValidator = accounts[1]
-
- const aggregatorAbi = loadContract_Solidity_V8('AggregatorV3Interface')
- const accessControllerAbi = loadContract_Solidity_V8('AccessControllerInterface')
-
- // Deploy the mock feed
- mockGasPriceFeed = await deployMockContract(deployer, aggregatorAbi.abi)
- await mockGasPriceFeed.mock.latestRoundData.returns(
- '73786976294838220258' /** roundId */,
- '96800000000' /** answer */,
- '163826896' /** startedAt */,
- '1638268960' /** updatedAt */,
- '73786976294838220258' /** answeredInRound */,
- )
-
- // Deploy the mock access controller
- mockAccessController = await deployMockContract(deployer, accessControllerAbi.abi)
-
- // Deploy the mock aggregator
- mockAggregator = await deployMockContract(deployer, aggregatorAbi.abi)
- await mockAggregator.mock.latestRoundData.returns(
- '73786976294838220258' /** roundId */,
- 1 /** answer */,
- '163826896' /** startedAt */,
- '1638268960' /** updatedAt */,
- '73786976294838220258' /** answeredInRound */,
- )
-
- const validatorArtifact = await loadContract_Solidity('emergency', 'StarknetValidator')
- const validatorFactory = await ethers.getContractFactoryFromArtifact(validatorArtifact, deployer)
-
- const mockStarknetMessagingArtifact = await loadContract_Solidity(
- 'mocks',
- 'MockStarknetMessaging',
- )
- mockStarknetMessengerFactory = await ethers.getContractFactoryFromArtifact(
- mockStarknetMessagingArtifact,
- deployer,
- )
-
- const messageCancellationDelay = 5 * 60 // seconds
- mockStarknetMessenger = await mockStarknetMessengerFactory.deploy(messageCancellationDelay)
- await mockStarknetMessenger.deployed()
-
- const UptimeFeedArtifact = loadContractPath(UPTIME_FEED_PATH, UPTIME_FEED_NAME)
-
- const mockUptimeFeedDeploy = new StarknetContract(
- UptimeFeedArtifact.abi,
- process.env.UPTIME_FEED as string,
- provider,
- )
-
- validator = await validatorFactory.deploy(
- mockStarknetMessenger.address,
- mockAccessController.address,
- mockGasPriceFeed.address,
- mockAggregator.address,
- mockUptimeFeedDeploy.address,
- 0,
- )
-
- console.log('Validator address: ', validator.address)
- const transaction = await account.execute(
- {
- contractAddress: mockUptimeFeedDeploy.address,
- entrypoint: 'set_l1_sender',
- calldata: [validator.address],
- },
- [UptimeFeedArtifact.abi],
- )
-
- await provider.waitForTransaction(transaction.transaction_hash)
-
- await validator.addAccess(eoaValidator.address)
- setInterval(callFunction, 60_000)
-}
-
-async function callFunction() {
- await starknet.devnet.loadL1MessagingContract(networkUrl, mockStarknetMessenger.address)
-
- await validator.connect(eoaValidator).validate(0, 0, 1, 1)
-
- const flushL1Response = await starknet.devnet.flush()
- flushL1Response.consumed_messages.from_l1
-}
-consumerValidator()
diff --git a/examples/contracts/aggregator-consumer/scripts/deploy_accounts.ts b/examples/contracts/aggregator-consumer/scripts/deploy_accounts.ts
deleted file mode 100644
index f89a93e..0000000
--- a/examples/contracts/aggregator-consumer/scripts/deploy_accounts.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import fs from 'fs'
-import dotenv from 'dotenv'
-import { ec, CallData } from 'starknet'
-import { loadContract_Account, createDeployerAccount, makeProvider } from './utils'
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-const ACCOUNT_NAME = 'Account'
-interface UserAccount {
- account: string
- privateKey: Uint8Array
-}
-let firstAccount: UserAccount
-
-export async function deployAccount() {
- firstAccount = await createAccount()
-
- fs.appendFile(__dirname + '/../.env', '\nACCOUNT_ADDRESS=' + firstAccount.account, function (
- err,
- ) {
- if (err) throw err
- })
- fs.appendFile(__dirname + '/../.env', '\nPRIVATE_KEY=' + firstAccount.privateKey, function (err) {
- if (err) throw err
- })
-}
-
-async function createAccount(): Promise {
- const provider = makeProvider()
-
- const predeployedAccount = createDeployerAccount(provider)
-
- const compiledAccount = loadContract_Account(ACCOUNT_NAME)
- const privateKey = ec.starkCurve.utils.randomPrivateKey()
-
- const starkKeyPub = ec.starkCurve.getStarkKey(privateKey)
- const OZaccountConstructorCallData = CallData.compile({ publicKey: starkKeyPub })
-
- const declareTx = await predeployedAccount.declare({
- classHash: '0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f',
- contract: compiledAccount,
- })
-
- console.log('Declare new Account...')
- await provider.waitForTransaction(declareTx.transaction_hash)
-
- const salt = '900080545022'
- const accountResponse = await predeployedAccount.deploy({
- classHash: '0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f',
- constructorCalldata: OZaccountConstructorCallData,
- salt,
- })
-
- console.log('Waiting for Tx to be Accepted on Starknet - OZ Account Deployment...')
- await provider.waitForTransaction(accountResponse.transaction_hash)
-
- return { account: accountResponse.contract_address[0], privateKey: privateKey }
-}
-
-deployAccount()
diff --git a/examples/contracts/aggregator-consumer/scripts/deploy_contracts.ts b/examples/contracts/aggregator-consumer/scripts/deploy_contracts.ts
deleted file mode 100644
index 6e5fff4..0000000
--- a/examples/contracts/aggregator-consumer/scripts/deploy_contracts.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { Contract } from 'starknet'
-import { loadContract, createDeployerAccount, loadContractPath, makeProvider } from './utils'
-import fs from 'fs'
-import dotenv from 'dotenv'
-
-const CONSUMER_NAME = 'Aggregator_consumer'
-
-const MOCK_NAME = 'MockAggregator'
-
-const PRICE_CONSUMER_NAME = 'Price_Consumer_With_Sequencer_Check'
-
-const UPTIME_FEED_PATH =
- '../../../../contracts/starknet-artifacts/src/plugin/cairo/emergency/SequencerUptimeFeed'
-const UPTIME_FEED_NAME = 'sequencer_uptime_feed'
-
-const DECIMALS = '18'
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-export async function deployContract() {
- const provider = makeProvider()
- const MockArtifact = loadContract(MOCK_NAME)
- const AggregatorArtifact = loadContract(CONSUMER_NAME)
- const priceConsumerArtifact = loadContract(PRICE_CONSUMER_NAME)
- const UptimeFeedArtifact = loadContractPath(UPTIME_FEED_PATH, UPTIME_FEED_NAME)
-
- const account = createDeployerAccount(provider)
-
- const declareDeployMock = await account.declareAndDeploy({
- contract: MockArtifact,
- constructorCalldata: [DECIMALS],
- })
-
- const mockDeploy = new Contract(
- MockArtifact.abi,
- declareDeployMock.deploy.contract_address,
- provider,
- )
-
- const declareDeployAggregator = await account.declareAndDeploy({
- contract: AggregatorArtifact,
- constructorCalldata: [mockDeploy.address as string],
- })
-
- const consumerDeploy = new Contract(
- AggregatorArtifact.abi,
- declareDeployAggregator.deploy.contract_address,
- provider,
- )
-
- const declareDeployUptimeFeed = await account.declareAndDeploy({
- contract: UptimeFeedArtifact,
- constructorCalldata: ['0', account.address],
- })
-
- const uptimeFeedDeploy = new Contract(
- UptimeFeedArtifact.abi,
- declareDeployUptimeFeed.deploy.contract_address,
- provider,
- )
-
- const declareDeployPriceConsumer = await account.declareAndDeploy({
- contract: priceConsumerArtifact,
- constructorCalldata: [uptimeFeedDeploy.address as string, mockDeploy.address as string],
- })
-
- const priceConsumerDeploy = new Contract(
- priceConsumerArtifact.abi,
- declareDeployPriceConsumer.deploy.contract_address,
- provider,
- )
-
- fs.appendFile(__dirname + '/../.env', '\nCONSUMER=' + consumerDeploy.address, function (err) {
- if (err) throw err
- })
- fs.appendFile(__dirname + '/../.env', '\nMOCK=' + mockDeploy.address, function (err) {
- if (err) throw err
- })
- fs.appendFile(
- __dirname + '/../.env',
- '\nPRICE_CONSUMER=' + priceConsumerDeploy.address,
- function (err) {
- if (err) throw err
- },
- )
- fs.appendFile(__dirname + '/../.env', '\nUPTIME_FEED=' + uptimeFeedDeploy.address, function (
- err,
- ) {
- if (err) throw err
- })
-}
-
-deployContract()
diff --git a/examples/contracts/aggregator-consumer/scripts/getLatestPrice.ts b/examples/contracts/aggregator-consumer/scripts/getLatestPrice.ts
deleted file mode 100644
index bfa3daf..0000000
--- a/examples/contracts/aggregator-consumer/scripts/getLatestPrice.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import dotenv from 'dotenv'
-import { createDeployerAccount, loadContract, loadContractPath, makeProvider } from './utils'
-import { Contract } from 'starknet'
-
-const PRICE_CONSUMER_NAME = 'Price_Consumer_With_Sequencer_Check'
-const UPTIME_FEED_PATH =
- '../../../../contracts/starknet-artifacts/src/plugin/cairo/emergency/SequencerUptimeFeed'
-const UPTIME_FEED_NAME = 'sequencer_uptime_feed'
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-export async function getLatestPrice() {
- const provider = makeProvider()
-
- const account = createDeployerAccount(provider)
-
- const priceConsumerArtifact = loadContract(PRICE_CONSUMER_NAME)
- const UptimeFeedArtifact = loadContractPath(UPTIME_FEED_PATH, UPTIME_FEED_NAME)
-
- const priceConsumer = new Contract(
- priceConsumerArtifact.abi,
- process.env.PRICE_CONSUMER as string,
- provider,
- )
- const uptimeFeed = new Contract(
- UptimeFeedArtifact.abi,
- process.env.UPTIME_FEED as string,
- provider,
- )
-
- const transaction = await account.execute(
- {
- contractAddress: uptimeFeed.address,
- entrypoint: 'add_access',
- calldata: [priceConsumer.address],
- },
- [UptimeFeedArtifact.abi],
- )
-
- console.log('Waiting for Tx to be Accepted on Starknet...')
- await provider.waitForTransaction(transaction.transaction_hash)
-
- const lat = await uptimeFeed.call('latest_round_data')
- const latestPrice = await account.callContract({
- contractAddress: priceConsumer.address,
- entrypoint: 'get_latest_price',
- calldata: [],
- })
-
- console.log('answer= ', latestPrice)
- return latestPrice
-}
-
-getLatestPrice()
diff --git a/examples/contracts/aggregator-consumer/scripts/readContinuously.ts b/examples/contracts/aggregator-consumer/scripts/readContinuously.ts
deleted file mode 100644
index 17a1160..0000000
--- a/examples/contracts/aggregator-consumer/scripts/readContinuously.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Contract, Account, CallContractResponse } from 'starknet'
-
-import { createDeployerAccount, loadContract, makeProvider } from './utils'
-import dotenv from 'dotenv'
-
-const CONTRACT_NAME = 'Aggregator_consumer'
-let account: Account
-let consumer: Contract
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-async function readContinuously() {
- const provider = makeProvider()
-
- account = createDeployerAccount(provider)
-
- const AggregatorArtifact = loadContract(CONTRACT_NAME)
-
- consumer = new Contract(AggregatorArtifact.abi, process.env.CONSUMER as string)
- setInterval(callFunction, 30000)
-}
-
-async function callFunction() {
- const latestRound = await account.callContract({
- contractAddress: consumer.address,
- entrypoint: 'readLatestRound',
- calldata: [],
- })
-
- const decimals = await account.callContract({
- contractAddress: consumer.address,
- entrypoint: 'readDecimals',
- calldata: [],
- })
- printResult(latestRound, decimals)
-}
-
-function printResult(latestRound: CallContractResponse, decimals: CallContractResponse) {
- console.log('round_id= ', parseInt(latestRound.result[0], 16))
- console.log('answer= ', parseInt(latestRound.result[1], 16))
- console.log('block_num= ', parseInt(latestRound.result[2], 16))
- console.log('staerted_at= ', parseInt(latestRound.result[3], 16))
- console.log('updated_at= ', parseInt(latestRound.result[4], 16))
- console.log('decimals= ', parseInt(decimals.result[0], 16))
-}
-
-readContinuously()
diff --git a/examples/contracts/aggregator-consumer/scripts/readDecimals.ts b/examples/contracts/aggregator-consumer/scripts/readDecimals.ts
deleted file mode 100644
index 4258cfd..0000000
--- a/examples/contracts/aggregator-consumer/scripts/readDecimals.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { Account, Contract } from 'starknet'
-import { createDeployerAccount, loadContract, makeProvider } from './utils'
-import dotenv from 'dotenv'
-
-const CONSUMER_NAME = 'Aggregator_consumer'
-let account: Account
-let consumer: Contract
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-export async function readDecimals() {
- const provider = makeProvider()
- account = createDeployerAccount(provider)
-
- const AggregatorArtifact = loadContract(CONSUMER_NAME)
- consumer = new Contract(AggregatorArtifact.abi, process.env.CONSUMER as string)
-
- const decimals = await account.callContract({
- contractAddress: consumer.address,
- entrypoint: 'readDecimals',
- calldata: [],
- })
-
- console.log('decimals= ', parseInt(decimals.result[0], 16))
- return parseInt(decimals.result[0], 16)
-}
-
-readDecimals()
diff --git a/examples/contracts/aggregator-consumer/scripts/readLatestRound.ts b/examples/contracts/aggregator-consumer/scripts/readLatestRound.ts
deleted file mode 100644
index e9c82c3..0000000
--- a/examples/contracts/aggregator-consumer/scripts/readLatestRound.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Account, Contract, CallContractResponse } from 'starknet'
-
-import { createDeployerAccount, loadContract, makeProvider } from './utils'
-import dotenv from 'dotenv'
-
-const CONSUMER_NAME = 'Aggregator_consumer'
-let account: Account
-let consumer: Contract
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-export async function readLatestRound() {
- const provider = makeProvider()
- account = createDeployerAccount(provider)
-
- const AggregatorArtifact = loadContract(CONSUMER_NAME)
- consumer = new Contract(AggregatorArtifact.abi, process.env.CONSUMER as string)
-
- const latestRound = await account.callContract({
- contractAddress: consumer.address,
- entrypoint: 'readLatestRound',
- calldata: [],
- })
- printResult(latestRound)
- return latestRound
-}
-
-function printResult(latestRound: CallContractResponse) {
- console.log('\nround_id= ', parseInt(latestRound.result[0], 16))
- console.log('answer= ', parseInt(latestRound.result[1], 16))
- console.log('block_num= ', parseInt(latestRound.result[2], 16))
- console.log('observation_timestamp= ', parseInt(latestRound.result[3], 16))
- console.log('transmission_timestamp= ', parseInt(latestRound.result[4], 16))
-}
-
-readLatestRound()
diff --git a/examples/contracts/aggregator-consumer/scripts/updateLatestRound.ts b/examples/contracts/aggregator-consumer/scripts/updateLatestRound.ts
deleted file mode 100644
index 95b0c05..0000000
--- a/examples/contracts/aggregator-consumer/scripts/updateLatestRound.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Account, Contract, Provider, ec, number } from 'starknet'
-import { loadContract, makeProvider } from './utils'
-import dotenv from 'dotenv'
-
-interface Transmission {
- answer: number
- block_num: number
- observation_timestamp: number
- transmission_timestamp: number
-}
-
-const CONTRACT_NAME = 'MockAggregator'
-let account: Account
-let mock: Contract
-let transmission: Transmission
-let provider: Provider
-
-dotenv.config({ path: __dirname + '/../.env' })
-
-const rl = require('readline').createInterface({
- input: process.stdin,
- output: process.stdout,
-})
-
-async function updateLatestRound() {
- provider = makeProvider()
-
- transmission = {
- answer: 0,
- block_num: 0,
- observation_timestamp: 0,
- transmission_timestamp: 0,
- }
-
- const keyPair = ec.getKeyPair(process.env.PRIVATE_KEY as string)
- account = new Account(provider, process.env.ACCOUNT_ADDRESS as string, keyPair)
-
- const MockArtifact = loadContract(CONTRACT_NAME)
-
- mock = new Contract(MockArtifact.abi, process.env.MOCK as string)
- transmission.answer = Number(await input('Enter a number for new answer: '))
- transmission.block_num = Number(await input('Enter a number for new block_num: '))
- transmission.observation_timestamp = Number(
- await input('Enter a number for new observation_timestamp: '),
- )
- transmission.transmission_timestamp = Number(
- await input('Enter a number for new transmission_timestamp: '),
- )
- rl.close()
-
- callFunction(transmission)
-}
-
-async function callFunction(transmission: Transmission) {
- const transaction = await account.execute(
- {
- contractAddress: mock.address,
- entrypoint: 'set_latest_round_data',
- calldata: [
- transmission.answer,
- transmission.block_num,
- transmission.observation_timestamp,
- transmission.transmission_timestamp,
- ],
- },
- [mock.abi],
- { maxFee: 1e18 },
- )
- console.log('Waiting for Tx to be Accepted on Starknet - Aggregator consumer Deployment...')
- await provider.waitForTransaction(transaction.transaction_hash)
-}
-
-function input(prompt: string) {
- return new Promise((callbackFn, errorFn) => {
- rl.question(prompt, (uinput: string) => {
- switch (isNaN(Number(uinput))) {
- case true:
- console.log('input is not a number we will use the default value of 1')
- uinput = '1'
- break
- default:
- break
- }
- callbackFn(uinput)
- })
- })
-}
-
-updateLatestRound()
diff --git a/examples/contracts/aggregator-consumer/scripts/utils.ts b/examples/contracts/aggregator-consumer/scripts/utils.ts
deleted file mode 100644
index 18bcaa7..0000000
--- a/examples/contracts/aggregator-consumer/scripts/utils.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import fs from 'fs'
-import dotenv from 'dotenv'
-import { CompiledContract, json, ec, Account, Provider, constants } from 'starknet'
-
-const DEVNET_NAME = 'devnet'
-
-export const loadContract = (name: string): CompiledContract => {
- return json.parse(
- fs
- .readFileSync(`${__dirname}/../starknet-artifacts/contracts/${name}.cairo/${name}.json`)
- .toString('ascii'),
- )
-}
-
-export const loadContractPath = (path: string, name: string): CompiledContract => {
- return json.parse(
- fs.readFileSync(`${__dirname}/${path}/${name}.cairo/${name}.json`).toString('ascii'),
- )
-}
-
-export const loadContract_Account = (name: string): CompiledContract => {
- return json.parse(
- fs
- .readFileSync(
- `${__dirname}/../../../../node_modules/@shardlabs/starknet-hardhat-plugin/dist/contract-artifacts/OpenZeppelinAccount/0.5.1/${name}.cairo/${name}.json`,
- )
- .toString('ascii'),
- )
-}
-
-export const loadContract_Solidity = (path: string, name: string): any => {
- return json.parse(
- fs
- .readFileSync(
- `${__dirname}/../../../../contracts/artifacts/src/plugin/solidity/${path}/${name}.sol/${name}.json`,
- )
- .toString('ascii'),
- )
-}
-export const loadContract_Solidity_V8 = (name: string): any => {
- return json.parse(
- fs
- .readFileSync(
- `${__dirname}/../../../../contracts/artifacts/@pluginv3.0/contracts/src/v0.8/interfaces/${name}.sol/${name}.json`,
- )
- .toString('ascii'),
- )
-}
-
-export function createDeployerAccount(provider: Provider): Account {
- dotenv.config({ path: __dirname + '/../.env' })
-
- const privateKey: string = process.env.DEPLOYER_PRIVATE_KEY as string
- const accountAddress: string = process.env.DEPLOYER_ACCOUNT_ADDRESS as string
- if (!privateKey || !accountAddress) {
- throw new Error('Deployer account address or private key is undefined!')
- }
-
- return new Account(provider, accountAddress, privateKey)
-}
-
-export const makeProvider = () => {
- const network = process.env.NETWORK || DEVNET_NAME
- if (network === DEVNET_NAME) {
- return new Provider({
- sequencer: {
- baseUrl: 'http://127.0.0.1:5050/',
- feederGatewayUrl: 'feeder_gateway',
- gatewayUrl: 'gateway',
- },
- })
- } else {
- return new Provider({
- sequencer: {
- network: constants.NetworkName.SN_GOERLI,
- },
- })
- }
-}
diff --git a/examples/contracts/aggregator-consumer/test/mock/Aggregator_consumer.test.ts b/examples/contracts/aggregator-consumer/test/mock/Aggregator_consumer.test.ts
deleted file mode 100644
index fe05600..0000000
--- a/examples/contracts/aggregator-consumer/test/mock/Aggregator_consumer.test.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { starknet } from 'hardhat'
-import { assert } from 'chai'
-import { StarknetContract, Account } from 'hardhat/types/runtime'
-import { account } from '@pluginv3.0/starknet'
-
-describe('ContractTestsMock', function () {
- this.timeout(600_000)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- let alice: Account
- let MockContract: StarknetContract
- let ConsumerContract: StarknetContract
-
- before(async () => {
- alice = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: alice.address, amount: 1e21 }])
- await alice.deployAccount()
-
- const decimals = 18
- const MockFactory = await starknet.getContractFactory('MockAggregator.cairo')
- await alice.declare(MockFactory)
-
- MockContract = await alice.deploy(MockFactory, { decimals: decimals })
-
- const ConsumerFactory = await starknet.getContractFactory('Aggregator_consumer.cairo')
- await alice.declare(ConsumerFactory)
-
- ConsumerContract = await alice.deploy(ConsumerFactory, {
- address: MockContract.address,
- })
- })
-
- it('should set and read latest round data successfully', async () => {
- await alice.invoke(MockContract, 'set_latest_round_data', {
- answer: 12,
- block_num: 1,
- observation_timestamp: 14325,
- transmission_timestamp: 87654,
- })
-
- const { round: round } = await ConsumerContract.call('readLatestRound', {})
- assert.equal(round.answer, 12)
- assert.equal(round.block_num, 1)
- assert.equal(round.started_at, 14325)
- assert.equal(round.updated_at, 87654)
- })
-
- it('should set and read latest round data successfully for the second time', async () => {
- await alice.invoke(MockContract, 'set_latest_round_data', {
- answer: 19,
- block_num: 2,
- observation_timestamp: 14345,
- transmission_timestamp: 62543,
- })
-
- const { round: round } = await ConsumerContract.call('readLatestRound', {})
- assert.equal(round.answer, 19)
- assert.equal(round.block_num, 2)
- assert.equal(round.started_at, 14345)
- assert.equal(round.updated_at, 62543)
- })
-
- it('should set and read latest round data successfully for the third time', async () => {
- await alice.invoke(MockContract, 'set_latest_round_data', {
- answer: 42,
- block_num: 3,
- observation_timestamp: 9876,
- transmission_timestamp: 27839,
- })
- const { round: round } = await ConsumerContract.call('readLatestRound', {})
- assert.equal(round.answer, 42)
- assert.equal(round.block_num, 3)
- assert.equal(round.started_at, 9876)
- assert.equal(round.updated_at, 27839)
- })
-
- it('should read Decimals successfully', async () => {
- const decimals = await ConsumerContract.call('readDecimals', {})
- assert.equal(decimals.decimals, 18)
- })
-})
diff --git a/examples/contracts/aggregator-consumer/test/mock/Examples_test.test.ts b/examples/contracts/aggregator-consumer/test/mock/Examples_test.test.ts
deleted file mode 100644
index d946cc5..0000000
--- a/examples/contracts/aggregator-consumer/test/mock/Examples_test.test.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { starknet, type } from 'hardhat'
-import { assert } from 'chai'
-import { account } from '@pluginv3.0/starknet'
-import fs from 'fs'
-import { readDecimals } from '../../scripts/readDecimals'
-import { readLatestRound } from '../../scripts/readLatestRound'
-import { createDeployerAccount, loadContract, makeProvider } from '../../scripts/utils'
-import { Contract, Provider, number } from 'starknet'
-import dotenv from 'dotenv'
-import { deployContract } from '../../scripts/deploy_contracts'
-import { getLatestPrice } from '../../scripts/getLatestPrice'
-import { deployAccount } from '../../scripts/deploy_accounts'
-import { consumerValidator } from '../../scripts/consumerValidator'
-
-describe('ExamplesTests', function () {
- dotenv.config({ path: __dirname + '/../../.env' })
-
- this.timeout(600_000)
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- let alice: type.Account
- let provider: Provider
-
- before(async () => {
- provider = makeProvider()
-
- alice = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([{ account: alice.address, amount: 1e21 }])
- await alice.deployAccount()
- fs.appendFile(
- __dirname + '/../../.env',
- '\nDEPLOYER_ACCOUNT_ADDRESS=' + alice.address,
- function (err) {
- if (err) throw err
- },
- )
- fs.appendFile(
- __dirname + '/../../.env',
- '\nDEPLOYER_PRIVATE_KEY=' + alice.privateKey,
- function (err) {
- if (err) throw err
- },
- )
- })
-
- it('should deploy contract', async () => {
- await deployContract()
- })
-
- it('should deploy account', async () => {
- await deployAccount()
- })
-
- it('should set and read latest round data successfully', async () => {
- const MockArtifact = loadContract('MockAggregator')
- const mock = new Contract(MockArtifact.abi, process.env.MOCK as string, provider)
-
- const bob = createDeployerAccount(provider)
- await funder.fund([{ account: bob.address, amount: 1e21 }])
- const transaction = await bob.execute(
- {
- contractAddress: mock.address,
- entrypoint: 'set_latest_round_data',
- calldata: [42, 3, 9876, 27839],
- },
- [mock.abi],
- )
- console.log('Waiting for Tx to be Accepted on Starknet - Aggregator consumer Deployment...')
- await provider.waitForTransaction(transaction.transaction_hash)
-
- const latestRound = await readLatestRound()
- assert.equal(parseInt(latestRound.result[1], 16), 42)
- assert.equal(parseInt(latestRound.result[2], 16), 3)
- assert.equal(parseInt(latestRound.result[3], 16), 9876)
- assert.equal(parseInt(latestRound.result[4], 16), 27839)
- })
-
- it('should read Decimals successfully', async () => {
- const decimals = await readDecimals()
- assert.equal(decimals, 18)
- })
-
- it('should test consumer validator', async () => {
- await consumerValidator()
- })
-
- it('should get latest price', async () => {
- const latestPrice = await getLatestPrice()
- assert.equal(parseInt(latestPrice.result[0], 16), 42)
- })
-})
diff --git a/examples/contracts/aggregator-consumer/tsconfig.json b/examples/contracts/aggregator-consumer/tsconfig.json
deleted file mode 100644
index 05f2b5d..0000000
--- a/examples/contracts/aggregator-consumer/tsconfig.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "dist",
- },
- "include": [
- "./hardhat.config.ts",
- "scripts/**/*"
- ],
- "exclude": [
- "dist",
- "**/*.spec.ts",
- "**/*.test.ts"
- ]
-}
diff --git a/examples/contracts/aggregator_consumer/.gitignore b/examples/contracts/aggregator_consumer/.gitignore
new file mode 100644
index 0000000..73aa31e
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/.gitignore
@@ -0,0 +1,2 @@
+target
+.snfoundry_cache/
diff --git a/examples/contracts/aggregator_consumer/Makefile b/examples/contracts/aggregator_consumer/Makefile
new file mode 100644
index 0000000..01dbccf
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/Makefile
@@ -0,0 +1,72 @@
+# The starknet-devnet-rs container version - this version
+# supports rpc v0.7 which is needed for snfoundry v0.20.1
+CONTAINER_VERSION="7743a089a33beb75d7012e4aa24745bee8ae0d71"
+
+export TESTNET_ACCOUNTS_FILE=~/.starknet_accounts/starknet_open_zeppelin_accounts.json
+export TESTNET_ACCOUNT_NAME=testnet-account
+
+export DEVNET_ACCOUNTS_FILE=$(shell pwd)/accounts.json
+export DEVNET_ACCOUNT_NAME=devnet-account
+
+# General Commands
+
+test:
+ @snforge test
+
+devnet:
+ @printf "\nStarting a local starknet devnet docker container:\n\n" \
+ && CONTAINER_VERSION="$(CONTAINER_VERSION)" bash ../../../ops/scripts/devnet-hardhat.sh
+
+# Account Management Commands
+
+create-account:
+ @printf "\nCreating starknet account details for testnet...\n\n" \
+ && sncast --profile testnet account create --name "$(TESTNET_ACCOUNT_NAME)" \
+ && printf "\nYour accounts:\n\n" \
+ && cat $(TESTNET_ACCOUNTS_FILE) \
+ && printf "\n\nYou can fund your account here: https://sepolia.starkgate.starknet.io\n"
+
+add-account:
+ @printf "\nImporting a prefunded account from starknet devnet container...\n\n" \
+ && sncast --profile devnet account add \
+ --name "$(DEVNET_ACCOUNT_NAME)" \
+ --address "0x4b3f4ba8c00a02b66142a4b1dd41a4dfab4f92650922a3280977b0f03c75ee1" \
+ --private-key "0x57b2f8431c772e647712ae93cc616638" \
+ && printf "\nYour accounts:\n\n" \
+ && cat $(DEVNET_ACCOUNTS_FILE) \
+
+deploy-account:
+ @sncast --profile testnet account deploy --name "$(TESTNET_ACCOUNT_NAME)" --max-fee 0x5af3107a3fff
+
+# MockAggregator Commands
+
+ma-deploy:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run deploy_mock_aggregator --no-state-file
+
+ma-set-latest-round:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run set_latest_round --no-state-file
+
+# Aggregator Commands
+
+agg-read-latest-round:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run read_latest_round --no-state-file
+
+agg-read-decimals:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run read_decimals --no-state-file
+
+# AggregatorConsumer commands
+
+ac-deploy:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run deploy_aggregator_consumer --no-state-file
+
+ac-read-answer:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run read_answer --no-state-file
+
+ac-set-answer:
+ @cd ./scripts && sncast --profile "$(NETWORK)" script run set_answer --no-state-file
+
+# Helpers
+
+devnet-deploy:
+ @make ma-deploy NETWORK=devnet && make ac-deploy NETWORK=devnet
+
diff --git a/examples/contracts/aggregator_consumer/README.md b/examples/contracts/aggregator_consumer/README.md
new file mode 100644
index 0000000..a9eb322
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/README.md
@@ -0,0 +1,238 @@
+# Examples
+
+## Overview
+
+In this directory you'll find three top-level folders:
+
+- `src/`: contains sample cairo contracts that demonstrate how one can integrate with Plugin's core starknet contracts.
+- `tests/`: contains cairo tests for the example contracts in `src/`. They showcase some simple usage patterns for the contracts.
+- `scripts/`: contains cairo scripts that allow you to interact with the example contracts over testnet or a local starknet devnet container.
+
+## Prerequisites
+
+To get started, ensure that you have the following tools installed on your machine:
+
+- [starknet-foundry (v0.21.0)](https://github.com/foundry-rs/starknet-foundry/releases/tag/v0.21.0)
+- [scarb (v2.6.4)](https://github.com/software-mansion/scarb/releases/tag/v2.6.4)
+
+## Tests
+
+To run all test cases in the `tests/` directory, you can use the following command:
+
+```sh
+make test
+```
+
+## Scripts
+
+### Setup
+
+#### Using a Local Starknet Docker Devnet
+
+If you would like to run the scripts against a local starknet devnet container:
+
+- First, execute the following command to run a [starknet-devnet-rs](https://github.com/0xSpaceShard/starknet-devnet-rs) container:
+
+ ```sh
+ make devnet
+ ```
+
+ If this command is re-run, it will fully stop the container and recreate it. This can be useful in case you'd like to restart from a completely clean state and re-run the deploy scripts.
+
+- The starknet devnet container comes with a set of prefunded accounts. In order to run the scripts, we'll need to add one of these accounts to a local `accounts.json` file. This can be done using the following command:
+
+ ```sh
+ make add-account
+ ```
+
+At this point you should be ready to start executing scripts! Feel free to move onto the next section.
+
+#### Using Testnet
+
+If you would like to run the scripts against testnet:
+
+- First, let's generate our account details. We can do this by running the following command:
+
+ ```sh
+ make create-account
+ ```
+
+ Once the account has been created, its info should be stored in an accounts file on your local machine (usually at `~/.starknet_accounts/starknet_open_zeppelin_accounts.json`).
+
+- Next, you'll need to fund the account with some tokens. This can be achieved by sending tokens from another starknet account or by bridging them with [StarkGate](https://sepolia.starkgate.starknet.io).
+
+- After you fund the account, you can deploy it to testnet using the following command:
+
+ ```sh
+ make deploy-account
+ ```
+
+At this point you should be ready to start executing scripts! Feel free to move onto the next section.
+
+### Running Scripts
+
+There are several different ways to use the scripts in this repo. We'll cover a few different options below.
+
+#### Reading Data from an Aggregator
+
+##### Devnet
+
+First, let's deploy a mock aggregator contract to our container:
+
+```sh
+make ma-deploy NETWORK=devnet
+```
+
+Under the hood this command will run a declare transaction followed by a deploy transaction for the MockAggregator contract. This command should output something similar to:
+
+```text
+Declaring and deploying MockAggregator
+Declaring contract...
+Transaction hash = 0x568d29d07128cba750845b57a4bb77a31f628b6f4288861d8b31d12e71e4c3b
+Class hash = 301563338814178704943249302673347019225052832575378055777678731916437560881
+Deploying contract...
+Transaction hash = 0xfbc49eb82894a704ce536ab904cdee0fd021b0fba335900f8b9b12cfcd005f
+MockAggregator deployed at address: 1566652744716179301065270359129119857774335542042051464747302084192731701184
+
+command: script run
+status: success
+```
+
+Once the MockAggregator is deployed, you can read the latest round data using the following command:
+
+```sh
+make agg-read-latest-round NETWORK=devnet
+```
+
+This should return an output like:
+
+```text
+Result::Ok(CallResult { data: [0, 0, 0, 0, 0] })
+command: script run
+status: success
+```
+
+In this case, there isn't any round data yet since we haven't added any mock data. To set the latest round data, you can run the following command:
+
+```sh
+make ma-set-latest-round NETWORK=devnet
+```
+
+This should result in an output like:
+
+```text
+Transaction hash = 0x5b57df1db0898caefd01f7d7ff9a300814ef8869a6c475f135d8b5d56e0e3a8
+Result::Ok(InvokeResult { transaction_hash: 2582232800348643522264958893576302212545891688073192089151947336582678242216 })
+command: script run
+status: success
+```
+
+Under the hood, this script sends a transaction to the network which calls `set_latest_round_data` on the `MockAggregator`. The data sent to the function is hardcoded in the script and can be modified in any way you like. Now when we read the latest round data:
+
+```sh
+make agg-read-latest-round NETWORK=devnet
+```
+
+We should see something like:
+
+```text
+Result::Ok(CallResult { data: [1, 1, 12345, 100000, 200000] })
+command: script run
+status: success
+```
+
+This array of values represents the following:
+
+```text
+[ 1, 1, 12345, 100000, 200000 ]
+[roundId, answer, block_num, observation_timestamp, transmittion_timestamp]
+```
+
+##### Testnet
+
+The steps and commands used for devnet can also be applied to testnet! However, there are a few noticeable differences:
+
+- You do not need to deploy a mock aggregator. If you already have the address of a pre-deployed aggregator, you can use it in the `read_latest_round.cairo` script!
+
+- For all the commands, make sure you use `NETWORK=testnet`.
+
+#### Deploying an Aggregator Consumer Contract
+
+##### Devnet
+
+First, let's restart our devnet container to ensure we're starting from a clean slate:
+
+```sh
+make devnet
+```
+
+Once the container is restarted, let's deploy the MockAggregator contract and the AggregatorConsumer contract to it:
+
+```sh
+make devnet-deploy
+```
+
+The AggregatorConsumer is a simple contract that can be used to store the latest answer of an Aggregator contract. It takes the address of an aggregator contract as input (in this case it is the MockAggregator), and it comes with the following methods:
+
+- `set_answer`: this function sets the answer to a new value.
+- `read_answer`: this function reads the answer from storage. The answer is initially set to 0 on deployment.
+- `read_ocr_address`: this function returns the address of the aggregator contract.
+
+At this point, the AggregatorConsumer's answer has not been set, so calling `read_answer` on the AggregatorConsumer contract will return 0. You can run the following commands to verify this:
+
+Command:
+
+```sh
+make ac-read-answer NETWORK=devnet
+```
+
+Output:
+
+
+```text
+Result::Ok(CallResult { data: [0] })
+command: script run
+status: success
+```
+
+To change this, let's use the set the MockAggregator's latest round data to some dummy values:
+
+```sh
+make ma-set-latest-round NETWORK=devnet
+```
+
+Now let's query the latest round data from the MockAggregator and store the latest round answer in the AggregatorConsumer:
+
+```sh
+make ac-set-answer NETWORK=devnet
+```
+
+Now, reading the AggregatorConsumer's answer returns a non-zero value:
+
+Command:
+
+```sh
+make ac-read-answer NETWORK=devnet
+```
+
+Output:
+
+```text
+Result::Ok(CallResult { data: [1] })
+command: script run
+status: success
+```
+
+##### Testnet
+
+The steps and commands used for devnet can also be applied to testnet! However, there are a few noticeable differences:
+
+- You do not need to use the `make devnet` command or the `make devnet-deploy` command. For contract deployment, you'll most likely want to use the address of a pre-deployed aggregator instead of the MockAggregator. If this is the case, you won't have control over the latest round data, so you can ignore the commands that interact with the MockAggregator (i.e. `make ma-set-latest-round`). For deployment, you can perform the following:
+ 1. note the address of the Aggregator contract you'd like to use
+ 1. input the address in the `deploy_aggregator_consumer.cairo` script
+ 1. run `make ac-deploy NETWORK=testnet`
+
+- For all the commands, make sure you use `NETWORK=testnet`.
+
+- The AggregatorConsumer scripts (e.g. `read_answer.cairo` and `set_answer.cairo`) contain the hardcoded address of the AggregatorConsumer for devnet. If you'd like to use these scripts on testnet, the hardcoded AggregatorConsumer address in these scripts will need to be swapped with the address that you receive from `make ac-deploy`. Keep in mind that the address that is printed from `make ac-deploy` may not be hex encoded - if this is the case you'll need to convert it to hex before adding it to the script.
+
diff --git a/examples/contracts/aggregator_consumer/Scarb.lock b/examples/contracts/aggregator_consumer/Scarb.lock
new file mode 100644
index 0000000..d261140
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/Scarb.lock
@@ -0,0 +1,82 @@
+# Code generated by scarb DO NOT EDIT.
+version = 1
+
+[[package]]
+name = "aggregator_consumer"
+version = "0.1.0"
+dependencies = [
+ "plugin",
+ "snforge_std",
+]
+
+[[package]]
+name = "alexandria_bytes"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+ "alexandria_math",
+]
+
+[[package]]
+name = "alexandria_data_structures"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_encoding",
+]
+
+[[package]]
+name = "alexandria_encoding"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_bytes",
+ "alexandria_math",
+ "alexandria_numeric",
+]
+
+[[package]]
+name = "alexandria_math"
+version = "0.2.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+]
+
+[[package]]
+name = "alexandria_numeric"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_math",
+ "alexandria_searching",
+]
+
+[[package]]
+name = "alexandria_searching"
+version = "0.1.0"
+source = "git+https://github.com/keep-starknet-strange/alexandria.git?rev=bcdca70afdf59c9976148e95cebad5cf63d75a7f#bcdca70afdf59c9976148e95cebad5cf63d75a7f"
+dependencies = [
+ "alexandria_data_structures",
+]
+
+[[package]]
+name = "plugin"
+version = "0.1.0"
+dependencies = [
+ "alexandria_bytes",
+ "alexandria_encoding",
+ "openzeppelin",
+ "snforge_std",
+]
+
+[[package]]
+name = "openzeppelin"
+version = "0.10.0"
+source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.10.0#d77082732daab2690ba50742ea41080eb23299d3"
+
+[[package]]
+name = "snforge_std"
+version = "0.27.0"
+source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.27.0#2d99b7c00678ef0363881ee0273550c44a9263de"
diff --git a/examples/contracts/aggregator_consumer/Scarb.toml b/examples/contracts/aggregator_consumer/Scarb.toml
new file mode 100644
index 0000000..7661e77
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/Scarb.toml
@@ -0,0 +1,28 @@
+# This project was generated using snforge init
+#
+# https://foundry-rs.github.io/starknet-foundry/appendix/snforge/init.html
+#
+
+[package]
+name = "aggregator_consumer"
+version = "0.1.0"
+cairo-version = "2.6.3"
+
+# [scripts]
+# test = "snforge test"
+
+# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
+
+[dependencies]
+snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.27.0" }
+plugin = { path = "../../../contracts" }
+starknet = ">=2.6.3"
+
+[lib]
+
+[[target.starknet-contract]]
+casm = true
+build-external-contracts = [
+ "plugin::emergency::sequencer_uptime_feed::SequencerUptimeFeed",
+ "plugin::ocr2::mocks::mock_aggregator::MockAggregator",
+]
diff --git a/examples/contracts/aggregator_consumer/scripts/Scarb.lock b/examples/contracts/aggregator_consumer/scripts/Scarb.lock
new file mode 100644
index 0000000..7e9b2bd
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/Scarb.lock
@@ -0,0 +1,41 @@
+# Code generated by scarb DO NOT EDIT.
+version = 1
+
+[[package]]
+name = "aggregator_consumer"
+version = "0.1.0"
+dependencies = [
+ "plugin",
+ "snforge_std",
+]
+
+[[package]]
+name = "plugin"
+version = "0.1.0"
+dependencies = [
+ "openzeppelin",
+]
+
+[[package]]
+name = "openzeppelin"
+version = "0.10.0"
+source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.10.0#d77082732daab2690ba50742ea41080eb23299d3"
+
+[[package]]
+name = "sncast_std"
+version = "0.21.0"
+source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.21.0#2996b8c1dd66b2715fc67e69578089f278a46790"
+
+[[package]]
+name = "snforge_std"
+version = "0.21.0"
+source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.21.0#2996b8c1dd66b2715fc67e69578089f278a46790"
+
+[[package]]
+name = "src"
+version = "0.1.0"
+dependencies = [
+ "aggregator_consumer",
+ "plugin",
+ "sncast_std",
+]
diff --git a/examples/contracts/aggregator_consumer/scripts/Scarb.toml b/examples/contracts/aggregator_consumer/scripts/Scarb.toml
new file mode 100644
index 0000000..50bc6f7
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/Scarb.toml
@@ -0,0 +1,24 @@
+[package]
+name = "src"
+version = "0.1.0"
+cairo-version = "2.6.3"
+
+# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
+
+[dependencies]
+sncast_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.21.0" }
+plugin = { path = "../../../../contracts" }
+aggregator_consumer = { path = "../" }
+starknet = ">=2.6.3"
+
+[lib]
+casm = true
+
+[[target.starknet-contract]]
+casm = true
+build-external-contracts = [
+ "plugin::emergency::sequencer_uptime_feed::SequencerUptimeFeed",
+ "plugin::ocr2::mocks::mock_aggregator::MockAggregator",
+ "aggregator_consumer::ocr2::consumer::AggregatorConsumer"
+]
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/aggregator.cairo b/examples/contracts/aggregator_consumer/scripts/src/aggregator.cairo
new file mode 100644
index 0000000..affdffa
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/aggregator.cairo
@@ -0,0 +1,2 @@
+mod read_latest_round;
+mod read_decimals;
diff --git a/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_decimals.cairo b/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_decimals.cairo
new file mode 100644
index 0000000..01067fd
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_decimals.cairo
@@ -0,0 +1,20 @@
+use sncast_std::{call, CallResult};
+
+use starknet::ContractAddress;
+
+fn main() {
+ // If you are using testnet, this address may need to be changed
+ // If you are using the local starknet-devnet-rs container, this can be left alone
+ let aggregator_address = 0x3c6f82da5dbfa89ec9dbe414f33d23d1720d15568e4a880afcc9b0c3d98d127
+ .try_into()
+ .unwrap();
+
+ let result = call(aggregator_address, selector!("decimals"), array![]);
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_latest_round.cairo b/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_latest_round.cairo
new file mode 100644
index 0000000..4a7c5c1
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/aggregator/read_latest_round.cairo
@@ -0,0 +1,20 @@
+use sncast_std::{call, CallResult};
+
+use starknet::ContractAddress;
+
+fn main() {
+ // If you are using testnet, this address may need to be changed
+ // If you are using the local starknet-devnet-rs container, this can be left alone
+ let aggregator_address = 0x3c6f82da5dbfa89ec9dbe414f33d23d1720d15568e4a880afcc9b0c3d98d127
+ .try_into()
+ .unwrap();
+
+ let result = call(aggregator_address, selector!("latest_round_data"), array![]);
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/consumer.cairo b/examples/contracts/aggregator_consumer/scripts/src/consumer.cairo
new file mode 100644
index 0000000..a7a56e7
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/consumer.cairo
@@ -0,0 +1,3 @@
+mod deploy_aggregator_consumer;
+mod read_answer;
+mod set_answer;
diff --git a/examples/contracts/aggregator_consumer/scripts/src/consumer/deploy_aggregator_consumer.cairo b/examples/contracts/aggregator_consumer/scripts/src/consumer/deploy_aggregator_consumer.cairo
new file mode 100644
index 0000000..4d55a13
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/consumer/deploy_aggregator_consumer.cairo
@@ -0,0 +1,57 @@
+use sncast_std::{
+ declare, deploy, DeclareResult, DeployResult, get_nonce, DisplayContractAddress,
+ DisplayClassHash
+};
+
+use starknet::{ContractAddress, ClassHash};
+
+fn declare_and_deploy(
+ contract_name: ByteArray, constructor_calldata: Array
+) -> DeployResult {
+ let mut class_hash: ClassHash =
+ 0x6d1dd0e5fa4e0284dcf341997f1d781bc2fb7d76ada684da7a2a33c38031df5
+ .try_into()
+ .unwrap();
+
+ println!("Declaring contract...");
+ let declare_result = declare(contract_name, Option::None, Option::None);
+ if declare_result.is_err() {
+ println!("{:?}", declare_result.unwrap_err());
+ } else {
+ class_hash = declare_result.unwrap().class_hash;
+ }
+ println!("Class hash = {:?}", class_hash);
+
+ println!("Deploying contract...");
+ let nonce = get_nonce('latest');
+ let salt = get_nonce('pending');
+ let deploy_result = deploy(
+ class_hash,
+ constructor_calldata,
+ Option::Some(salt),
+ true,
+ Option::None,
+ Option::Some(nonce)
+ );
+ if deploy_result.is_err() {
+ println!("{:?}", deploy_result.unwrap_err());
+ panic_with_felt252('deploy failed');
+ }
+
+ return deploy_result.unwrap();
+}
+
+fn main() {
+ // Point this to the address of the aggregator contract you'd like to use
+ let aggregator_address: ContractAddress =
+ 0x3c6f82da5dbfa89ec9dbe414f33d23d1720d15568e4a880afcc9b0c3d98d127
+ .try_into()
+ .unwrap();
+
+ println!("\nDeclaring and deploying AggregatorConsumer");
+ let mut calldata = ArrayTrait::new();
+ calldata.append(aggregator_address.into());
+ let consumer = declare_and_deploy("AggregatorConsumer", calldata);
+ println!("AggregatorConsumer deployed at address: {}\n", consumer.contract_address);
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/consumer/read_answer.cairo b/examples/contracts/aggregator_consumer/scripts/src/consumer/read_answer.cairo
new file mode 100644
index 0000000..7434316
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/consumer/read_answer.cairo
@@ -0,0 +1,20 @@
+use sncast_std::{call, CallResult};
+
+use starknet::ContractAddress;
+
+fn main() {
+ // If you are using testnet, this address may need to be changed
+ // If you are using the local starknet-devnet-rs container, this can be left alone
+ let consumer_address = 0x56e078ee90929f13f2ca83545c71b98136c99b22822ada66ad2aff9595439fc
+ .try_into()
+ .unwrap();
+
+ let result = call(consumer_address, selector!("read_answer"), array![]);
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/consumer/set_answer.cairo b/examples/contracts/aggregator_consumer/scripts/src/consumer/set_answer.cairo
new file mode 100644
index 0000000..bdf0e1d
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/consumer/set_answer.cairo
@@ -0,0 +1,53 @@
+use sncast_std::{invoke, InvokeResult, call, CallResult, get_nonce};
+
+use starknet::ContractAddress;
+
+fn main() {
+ // If you are using testnet, this address may need to be changed
+ // If you are using the local starknet-devnet-rs container, this can be left alone
+ let consumer_address = 0x56e078ee90929f13f2ca83545c71b98136c99b22822ada66ad2aff9595439fc
+ .try_into()
+ .unwrap();
+
+ // Reads the aggregator address from the AggregatorConsumer
+ let read_ocr_address = call(consumer_address, selector!("read_ocr_address"), array![]);
+ if read_ocr_address.is_err() {
+ println!("{:?}", read_ocr_address.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", read_ocr_address);
+ }
+
+ // Queries the aggregator for the latest round data
+ let mut read_ocr_address_data = read_ocr_address.unwrap().data.span();
+ let aggregator_address = Serde::<
+ starknet::ContractAddress
+ >::deserialize(ref read_ocr_address_data)
+ .unwrap();
+ let latest_round = call(aggregator_address, selector!("latest_round_data"), array![]);
+ if latest_round.is_err() {
+ println!("{:?}", latest_round.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", latest_round);
+ }
+
+ // Uses the latest round data to set a new answer on the AggregatorConsumer
+ let mut latest_round_data = latest_round.unwrap().data.span();
+ let round = Serde::::deserialize(ref latest_round_data)
+ .unwrap();
+ let result = invoke(
+ consumer_address,
+ selector!("set_answer"),
+ array![round.answer.into()],
+ Option::None,
+ Option::Some(get_nonce('pending'))
+ );
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('invoke failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/example.cairo b/examples/contracts/aggregator_consumer/scripts/src/example.cairo
new file mode 100644
index 0000000..3d64bde
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/example.cairo
@@ -0,0 +1,15 @@
+use sncast_std::{call, CallResult};
+
+fn main() {
+ let address = 0x775ee7f2f0b3e15953f4688f7a2ce5a0d1e7c8e18e5f929d461c037f14b690e
+ .try_into()
+ .unwrap();
+ let result = call(address, selector!("description"), array![]);
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('call failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/lib.cairo b/examples/contracts/aggregator_consumer/scripts/src/lib.cairo
new file mode 100644
index 0000000..f4dee19
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/lib.cairo
@@ -0,0 +1,4 @@
+mod mock_aggregator;
+mod aggregator;
+mod consumer;
+mod example;
diff --git a/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator.cairo b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator.cairo
new file mode 100644
index 0000000..e403e77
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator.cairo
@@ -0,0 +1,2 @@
+mod deploy_mock_aggregator;
+mod set_latest_round;
diff --git a/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/deploy_mock_aggregator.cairo b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/deploy_mock_aggregator.cairo
new file mode 100644
index 0000000..e3ab4e9
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/deploy_mock_aggregator.cairo
@@ -0,0 +1,52 @@
+use sncast_std::{
+ declare, deploy, DeclareResult, DeployResult, get_nonce, DisplayContractAddress,
+ DisplayClassHash
+};
+
+use starknet::{ContractAddress, ClassHash};
+
+fn declare_and_deploy(
+ contract_name: ByteArray, constructor_calldata: Array
+) -> DeployResult {
+ let mut class_hash: ClassHash =
+ 0x728d8a221e2204c88df0642b7c6dcee60f7c3d3b3d5c190cac1ceba5baf15e8
+ .try_into()
+ .unwrap();
+
+ println!("Declaring contract...");
+ let declare_result = declare(contract_name, Option::None, Option::None);
+ if declare_result.is_err() {
+ println!("{:?}", declare_result.unwrap_err());
+ } else {
+ class_hash = declare_result.unwrap().class_hash;
+ }
+ println!("Class hash = {:?}", class_hash);
+
+ println!("Deploying contract...");
+ let nonce = get_nonce('latest');
+ let salt = get_nonce('pending');
+ let deploy_result = deploy(
+ class_hash,
+ constructor_calldata,
+ Option::Some(salt),
+ true,
+ Option::None,
+ Option::Some(nonce)
+ );
+ if deploy_result.is_err() {
+ println!("{:?}", deploy_result.unwrap_err());
+ panic_with_felt252('deploy failed');
+ }
+
+ return deploy_result.unwrap();
+}
+
+fn main() {
+ let decimals = 16;
+ println!("\nDeclaring and deploying MockAggregator");
+ let mut calldata = ArrayTrait::new();
+ calldata.append(decimals.into());
+ let mock_aggregator = declare_and_deploy("MockAggregator", calldata);
+ println!("MockAggregator deployed at address: {}\n", mock_aggregator.contract_address);
+}
+
diff --git a/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/set_latest_round.cairo b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/set_latest_round.cairo
new file mode 100644
index 0000000..d5a2a01
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/scripts/src/mock_aggregator/set_latest_round.cairo
@@ -0,0 +1,33 @@
+use sncast_std::{invoke, InvokeResult, get_nonce};
+
+use starknet::ContractAddress;
+
+fn main() {
+ // If you are using testnet, this address may need to be changed
+ // If you are using the local starknet-devnet-rs container, this can be left alone
+ let mock_aggregator_address = 0x3c6f82da5dbfa89ec9dbe414f33d23d1720d15568e4a880afcc9b0c3d98d127
+ .try_into()
+ .unwrap();
+
+ // Feel free to modify these
+ let answer = 1;
+ let block_num = 12345;
+ let observation_timestamp = 1711716556;
+ let transmission_timestamp = 1711716514;
+
+ let result = invoke(
+ mock_aggregator_address,
+ selector!("set_latest_round_data"),
+ array![answer, block_num, observation_timestamp, transmission_timestamp],
+ Option::None,
+ Option::Some(get_nonce('pending'))
+ );
+
+ if result.is_err() {
+ println!("{:?}", result.unwrap_err());
+ panic_with_felt252('invoke failed');
+ } else {
+ println!("{:?}", result);
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/snfoundry.toml b/examples/contracts/aggregator_consumer/snfoundry.toml
new file mode 100644
index 0000000..e9a3403
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/snfoundry.toml
@@ -0,0 +1,16 @@
+# A full list of RPC endpoints can be found here:
+#
+# https://blastapi.io/public-api/starknet
+#
+[sncast.devnet]
+url = "http://127.0.0.1:5050/rpc"
+accounts-file = "$DEVNET_ACCOUNTS_FILE"
+account = "$DEVNET_ACCOUNT_NAME"
+hex-format = true
+
+[sncast.testnet]
+url = "https://starknet-sepolia.public.blastapi.io/rpc/v0_7"
+accounts-file = "$TESTNET_ACCOUNTS_FILE"
+account = "$TESTNET_ACCOUNT_NAME"
+hex-format = true
+
diff --git a/examples/contracts/aggregator_consumer/src/lib.cairo b/examples/contracts/aggregator_consumer/src/lib.cairo
new file mode 100644
index 0000000..ea17438
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/src/lib.cairo
@@ -0,0 +1,2 @@
+pub mod ocr2;
+
diff --git a/examples/contracts/aggregator_consumer/src/ocr2.cairo b/examples/contracts/aggregator_consumer/src/ocr2.cairo
new file mode 100644
index 0000000..8947aa7
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/src/ocr2.cairo
@@ -0,0 +1,2 @@
+pub mod price_consumer;
+pub mod consumer;
diff --git a/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo b/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo
new file mode 100644
index 0000000..968de25
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo
@@ -0,0 +1,52 @@
+#[starknet::interface]
+pub trait IAggregatorConsumer {
+ fn read_latest_round(self: @TContractState) -> plugin::ocr2::aggregator::Round;
+ fn read_ocr_address(self: @TContractState) -> starknet::ContractAddress;
+ fn read_answer(self: @TContractState) -> u128;
+ fn set_answer(ref self: TContractState, answer: u128);
+}
+
+#[starknet::contract]
+mod AggregatorConsumer {
+ use starknet::ContractAddress;
+ use traits::Into;
+
+ use plugin::ocr2::aggregator::Round;
+
+ use plugin::ocr2::aggregator_proxy::IAggregator;
+ use plugin::ocr2::aggregator_proxy::IAggregatorDispatcher;
+ use plugin::ocr2::aggregator_proxy::IAggregatorDispatcherTrait;
+
+ #[storage]
+ struct Storage {
+ _ocr_address: ContractAddress,
+ _answer: u128,
+ }
+
+ #[constructor]
+ fn constructor(ref self: ContractState, ocr_address: ContractAddress) {
+ self._ocr_address.write(ocr_address);
+ self._answer.write(0);
+ }
+
+ #[abi(embed_v0)]
+ impl AggregatorConsumerImpl of super::IAggregatorConsumer {
+ fn read_latest_round(self: @ContractState) -> Round {
+ return IAggregatorDispatcher { contract_address: self._ocr_address.read() }
+ .latest_round_data();
+ }
+
+
+ fn set_answer(ref self: ContractState, answer: u128) {
+ self._answer.write(answer);
+ }
+
+ fn read_answer(self: @ContractState) -> u128 {
+ return self._answer.read();
+ }
+
+ fn read_ocr_address(self: @ContractState) -> ContractAddress {
+ return self._ocr_address.read();
+ }
+ }
+}
diff --git a/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo b/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo
new file mode 100644
index 0000000..50ec4fd
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo
@@ -0,0 +1,68 @@
+#[starknet::interface]
+pub trait IAggregatorPriceConsumer {
+ fn get_latest_price(self: @TContractState) -> u128;
+}
+
+#[starknet::contract]
+mod AggregatorPriceConsumer {
+ use box::BoxTrait;
+ use starknet::ContractAddress;
+ use zeroable::Zeroable;
+ use traits::Into;
+
+ use plugin::ocr2::aggregator::Round;
+ use plugin::ocr2::aggregator_proxy::IAggregator;
+ use plugin::ocr2::aggregator_proxy::IAggregatorDispatcher;
+ use plugin::ocr2::aggregator_proxy::IAggregatorDispatcherTrait;
+
+ #[storage]
+ struct Storage {
+ _uptime_feed_address: ContractAddress,
+ _aggregator_address: ContractAddress,
+ }
+
+ // Sequencer-aware aggregator consumer
+ // retrieves the latest price from the data feed only if
+ // the uptime feed is not stale (stale = older than 60 seconds)
+ #[constructor]
+ fn constructor(
+ ref self: ContractState,
+ uptime_feed_address: ContractAddress,
+ aggregator_address: ContractAddress
+ ) {
+ assert(!uptime_feed_address.is_zero(), 'uptime feed is 0');
+ assert(!aggregator_address.is_zero(), 'aggregator is 0');
+ self._uptime_feed_address.write(uptime_feed_address);
+ self._aggregator_address.write(aggregator_address);
+ }
+
+
+ #[abi(embed_v0)]
+ impl AggregatorPriceConsumerImpl of super::IAggregatorPriceConsumer {
+ fn get_latest_price(self: @ContractState) -> u128 {
+ assert_sequencer_healthy(self);
+ let round = IAggregatorDispatcher { contract_address: self._aggregator_address.read() }
+ .latest_round_data();
+ round.answer
+ }
+ }
+
+ fn assert_sequencer_healthy(self: @ContractState) {
+ let round = IAggregatorDispatcher { contract_address: self._uptime_feed_address.read() }
+ .latest_round_data();
+ let timestamp = starknet::get_block_info().unbox().block_timestamp;
+
+ // After 60 sec the report is considered stale
+ let report_stale = timestamp - round.updated_at > 60_u64;
+
+ // 0 if the sequencer is up and 1 if it is down. No other options besides 1 and 0
+ match round.answer.into() {
+ 0 => { assert(!report_stale, 'L2 seq up & report stale'); },
+ _ => {
+ assert(!report_stale, 'L2 seq down & report stale');
+ assert(false, 'L2 seq down & report ok');
+ }
+ }
+ }
+}
+
diff --git a/examples/contracts/aggregator_consumer/tests/test_consumer.cairo b/examples/contracts/aggregator_consumer/tests/test_consumer.cairo
new file mode 100644
index 0000000..4205459
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/tests/test_consumer.cairo
@@ -0,0 +1,125 @@
+use snforge_std::{declare, ContractClassTrait};
+
+use plugin::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcherTrait;
+use plugin::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcher;
+use plugin::ocr2::aggregator_proxy::IAggregatorDispatcherTrait;
+use plugin::ocr2::aggregator_proxy::IAggregatorDispatcher;
+
+use aggregator_consumer::ocr2::consumer::IAggregatorConsumerDispatcherTrait;
+use aggregator_consumer::ocr2::consumer::IAggregatorConsumerDispatcher;
+
+use starknet::ContractAddress;
+
+fn deploy_mock_aggregator(decimals: u8) -> ContractAddress {
+ let mut calldata = ArrayTrait::new();
+ calldata.append(decimals.into());
+
+ let contract = declare("MockAggregator").unwrap();
+
+ let (contract_address, _) = contract.deploy(@calldata).unwrap();
+
+ contract_address
+}
+
+fn deploy_consumer(aggregator_address: ContractAddress) -> ContractAddress {
+ let mut calldata = ArrayTrait::new();
+ calldata.append(aggregator_address.into());
+
+ let contract = declare("AggregatorConsumer").unwrap();
+
+ let (contract_address, _) = contract.deploy(@calldata).unwrap();
+
+ contract_address
+}
+
+#[test]
+fn test_read_decimals() {
+ // Deploys the mock aggregator
+ let decimals = 16;
+ let mock_aggregator_address = deploy_mock_aggregator(decimals);
+ let aggregator_dispatcher = IAggregatorDispatcher { contract_address: mock_aggregator_address };
+
+ // Let's make sure the constructor arguments were passed in correctly
+ assert(decimals == aggregator_dispatcher.decimals(), 'Invalid decimals');
+}
+#[test]
+fn test_set_and_read_latest_round() {
+ // Deploys the mock aggregator
+ let mock_aggregator_address = deploy_mock_aggregator(16);
+ let mock_aggregator_dispatcher = IMockAggregatorDispatcher {
+ contract_address: mock_aggregator_address
+ };
+ let aggregator_dispatcher = IAggregatorDispatcher { contract_address: mock_aggregator_address };
+
+ // No round data has been initialized, so reading the latest round should return no data
+ let empty_latest_round = aggregator_dispatcher.latest_round_data();
+ assert(empty_latest_round.round_id == 0, 'round_id != 0');
+ assert(empty_latest_round.answer == 0, 'answer != 0');
+ assert(empty_latest_round.block_num == 0, 'block_num != 0');
+ assert(empty_latest_round.started_at == 0, 'started_at != 0');
+ assert(empty_latest_round.updated_at == 0, 'updated_at != 0');
+
+ // Now let's set the latest round data to some random values
+ let answer = 1;
+ let block_num = 12345;
+ let observation_timestamp = 100000;
+ let transmission_timestamp = 200000;
+ mock_aggregator_dispatcher
+ .set_latest_round_data(answer, block_num, observation_timestamp, transmission_timestamp);
+
+ // The latest round should now have some data
+ let latest_round = aggregator_dispatcher.latest_round_data();
+ assert(latest_round.round_id == 1, 'round_id != 1');
+ assert(latest_round.answer == answer, 'bad answer');
+ assert(latest_round.block_num == block_num, 'bad block_num');
+ assert(latest_round.started_at == observation_timestamp, 'bad started_at');
+ assert(latest_round.updated_at == transmission_timestamp, 'bad updated_at');
+}
+
+#[test]
+fn test_set_and_read_answer() {
+ // Deploys the mock aggregator
+ let mock_aggregator_address = deploy_mock_aggregator(16);
+ let mock_aggregator_dispatcher = IMockAggregatorDispatcher {
+ contract_address: mock_aggregator_address
+ };
+
+ // Deploys the consumer
+ let consumer_address = deploy_consumer(mock_aggregator_address);
+ let consumer_dispatcher = IAggregatorConsumerDispatcher { contract_address: consumer_address };
+
+ // Let's make sure the AggregatorConsumer was initialized correctly
+ assert(
+ consumer_dispatcher.read_ocr_address() == mock_aggregator_address, 'Invalid OCR address'
+ );
+ assert(consumer_dispatcher.read_answer() == 0, 'Invalid initial answer');
+
+ // No round data has been initialized, so reading the latest round should return no data
+ let empty_latest_round = consumer_dispatcher.read_latest_round();
+ assert(empty_latest_round.round_id == 0, 'round_id != 0');
+ assert(empty_latest_round.answer == 0, 'answer != 0');
+ assert(empty_latest_round.block_num == 0, 'block_num != 0');
+ assert(empty_latest_round.started_at == 0, 'started_at != 0');
+ assert(empty_latest_round.updated_at == 0, 'updated_at != 0');
+
+ // Now let's set the latest round data to some random values
+ let answer = 1;
+ let block_num = 12345;
+ let observation_timestamp = 100000;
+ let transmission_timestamp = 200000;
+ mock_aggregator_dispatcher
+ .set_latest_round_data(answer, block_num, observation_timestamp, transmission_timestamp);
+
+ // The consumer should be able to query the aggregator for the new latest round data
+ let latest_round = consumer_dispatcher.read_latest_round();
+ assert(latest_round.round_id == 1, 'round_id != 1');
+ assert(latest_round.answer == answer, 'bad answer');
+ assert(latest_round.block_num == block_num, 'bad block_num');
+ assert(latest_round.started_at == observation_timestamp, 'bad started_at');
+ assert(latest_round.updated_at == transmission_timestamp, 'bad updated_at');
+
+ // Now let's test that we can set the answer
+ consumer_dispatcher.set_answer(latest_round.answer);
+ assert(answer == consumer_dispatcher.read_answer(), 'Invalid answer');
+}
+
diff --git a/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo b/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo
new file mode 100644
index 0000000..2df3600
--- /dev/null
+++ b/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo
@@ -0,0 +1,99 @@
+use plugin::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcherTrait;
+use plugin::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcher;
+use plugin::libraries::access_control::IAccessControllerDispatcherTrait;
+use plugin::libraries::access_control::IAccessControllerDispatcher;
+use plugin::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcherTrait;
+use plugin::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcher;
+
+use aggregator_consumer::ocr2::price_consumer::IAggregatorPriceConsumerDispatcherTrait;
+use aggregator_consumer::ocr2::price_consumer::IAggregatorPriceConsumerDispatcher;
+
+use starknet::contract_address_const;
+use starknet::get_caller_address;
+use starknet::ContractAddress;
+
+use snforge_std::{
+ declare, ContractClassTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global
+};
+
+fn deploy_mock_aggregator(decimals: u8) -> ContractAddress {
+ let mut calldata = ArrayTrait::new();
+ calldata.append(decimals.into());
+ let (contract_address, _) = declare("MockAggregator").unwrap().deploy(@calldata).unwrap();
+ contract_address
+}
+
+fn deploy_uptime_feed(initial_status: u128, owner_address: ContractAddress) -> ContractAddress {
+ let mut calldata = ArrayTrait::new();
+ calldata.append(initial_status.into());
+ calldata.append(owner_address.into());
+ let (contract_address, _) = declare("SequencerUptimeFeed").unwrap().deploy(@calldata).unwrap();
+ contract_address
+}
+
+fn deploy_price_consumer(
+ uptime_feed_address: ContractAddress, aggregator_address: ContractAddress
+) -> ContractAddress {
+ let mut calldata = ArrayTrait::new();
+ calldata.append(uptime_feed_address.into());
+ calldata.append(aggregator_address.into());
+ let (contract_address, _) = declare("AggregatorPriceConsumer")
+ .unwrap()
+ .deploy(@calldata)
+ .unwrap();
+ contract_address
+}
+
+#[test]
+fn test_get_latest_price() {
+ // Defines helper variables
+ let owner = contract_address_const::<1>();
+ let init_status = 0;
+ let decimals = 18;
+
+ // Deploys contracts
+ let mock_aggregator_address = deploy_mock_aggregator(decimals);
+ let uptime_feed_address = deploy_uptime_feed(init_status, owner);
+ let price_consumer_address = deploy_price_consumer(
+ uptime_feed_address, mock_aggregator_address
+ );
+
+ // Adds the price consumer contract to the sequencer uptime feed access control list
+ // which allows the price consumer to call the get_latest_price function
+ start_cheat_caller_address_global(owner);
+ // start_prank(CheatTarget::All, owner);
+ IAccessControllerDispatcher { contract_address: uptime_feed_address }
+ .add_access(price_consumer_address);
+
+ // The get_latest_price function returns the mock aggregator's latest round answer. At
+ // this point in the test, there is only one round that is initialized and that is the
+ // one that the sequencer uptime feed creates when it is deployed. In its constructor,
+ // a new round is initialized using its initial status as the round's answer, so the
+ // latest price should be the initial status that was passed into the sequencer uptime
+ // feed's constructor.
+ start_cheat_caller_address_global(price_consumer_address);
+ // start_prank(CheatTarget::All, price_consumer_address);
+ let latest_price = IAggregatorPriceConsumerDispatcher {
+ contract_address: price_consumer_address
+ }
+ .get_latest_price();
+ assert(latest_price == init_status, 'latest price is incorrect');
+
+ // Now let's update the round
+ stop_cheat_caller_address_global();
+ let answer = 1;
+ let block_num = 12345;
+ let observation_timestamp = 100000;
+ let transmission_timestamp = 200000;
+ IMockAggregatorDispatcher { contract_address: mock_aggregator_address }
+ .set_latest_round_data(answer, block_num, observation_timestamp, transmission_timestamp);
+
+ // This should now return the updated answer
+ start_cheat_caller_address_global(price_consumer_address);
+ let updated_latest_price = IAggregatorPriceConsumerDispatcher {
+ contract_address: price_consumer_address
+ }
+ .get_latest_price();
+ assert(updated_latest_price == answer, 'updated price is incorrect');
+}
+
diff --git a/examples/contracts/proxy-consumer/.gitignore b/examples/contracts/proxy-consumer/.gitignore
deleted file mode 100644
index 80b6296..0000000
--- a/examples/contracts/proxy-consumer/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-cache/
-starknet-artifacts/
diff --git a/examples/contracts/proxy-consumer/README.md b/examples/contracts/proxy-consumer/README.md
deleted file mode 100644
index 4250ef8..0000000
--- a/examples/contracts/proxy-consumer/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-This is a simple example for how to read Plugin data feeds on Starknet.
-
-### Requirements
-
-Set up your environment to run the examples.
-
-1. [Setup your local Starknet environment](https://starknet.io/docs/quickstart.html). Note that a Python version in the `>=3.6 <=3.9` range is required for compiling and deploying contracts on-chain. The [`cairo-lang` Python package](https://pypi.org/project/cairo-lang/) is not compatible with newer versions of Python as of the [`cairo-lang` 0.10.3](https://pypi.org/project/cairo-lang/0.10.3/) package. Check [starknet.io](https://starknet.io/docs/quickstart.html) for the latest requirements.
-1. [Set up a Starknet account](https://starknet.io/docs/hello_starknet/account_setup.html) on Starknet's `alpha-goerli` network and fund it with [testnet ETH](https://faucet.goerli.starknet.io/). These examples expect the OpenZeppelin wallet, which stores your addresses and private keys at `~/.starknet_accounts/starknet_open_zeppelin_accounts.json` by default.
-1. [Install NodeJS](https://nodejs.org/en/download/) in the version in the `>=14 <=18` version range.
-1. [Install Yarn](https://classic.yarnpkg.com/lang/en/docs/install/).
-1. Clone the [goplugin/plugin-starknet](https://github.com/goplugin/plugin-starknet) repository, which includes the example contracts for this guide: `git clone https://github.com/goplugin/plugin-starknet.git`
-1. In your clone of the [plugin-starknet](https://github.com/goplugin/plugin-starknet) repository, change directories to the proxy consumer example: `cd ./plugin-starknet/examples/contracts/proxy-consumer/`
-1. Run `yarn install` to install the required packages including [Starknet.js](https://www.starknetjs.com/), [HardHat](https://hardhat.org/), and the [Starknet Hardhat Plugin](https://shard-labs.github.io/starknet-hardhat-plugin/).
-
-### Running the on-chain example
-
-1. Find the your account address and private key for your funded Starknet testnet account. By default, the OpenZeppelin wallet contains these values at `~/.starknet_accounts/starknet_open_zeppelin_accounts.json`.
-1. Export your address to the `DEPLOYER_ACCOUNT_ADDRESS` environment variable and your private key to the `DEPLOYER_PRIVATE_KEY` environment variable.
-
- ```shell
- export DEPLOYER_ACCOUNT_ADDRESS=
- ```
-
- ```shell
- export DEPLOYER_PRIVATE_KEY=
- ```
-
-1. Run `yarn build` to run Hardhat and create `./starknet-artifacts/` with the compiled contracts. Hardhat uses the [`@shardlabs/starknet-hardhat-plugin` package](https://www.npmjs.com/package/@shardlabs/starknet-hardhat-plugin) for this step.
-1. Run `yarn deploy` to deploy the example consumer contract to the Starknet Goerli testnet. The console prints the contract address and transaction hash.
-1. Run `yarn readLatestRound ` to send an invoke transaction to the deployed contract. Specify the contract address printed by the deploy step. The deployed contract reads the latest round data from the proxy, stores the values, and prints the resulting values.
-
-### Running the off-chain example
-
-This example simply reads the proxy contract to get the latest values with no account or contract compiling steps required.
-
-1. Run `yarn readLatestRoundOffChain`.
diff --git a/examples/contracts/proxy-consumer/contracts/Proxy_consumer.cairo b/examples/contracts/proxy-consumer/contracts/Proxy_consumer.cairo
deleted file mode 100644
index 0c75a92..0000000
--- a/examples/contracts/proxy-consumer/contracts/Proxy_consumer.cairo
+++ /dev/null
@@ -1,50 +0,0 @@
-%lang starknet
-
-from starkware.cairo.common.cairo_builtins import HashBuiltin
-from starkware.cairo.common.math import assert_not_zero
-from plugin.cairo.ocr2.IAggregator import IAggregator, Round
-
-@storage_var
-func consumer_proxy_address() -> (address: felt) {
-}
-
-@storage_var
-func feed_data() -> (data: Round) {
-}
-
-@constructor
-func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
- proxy_address: felt
-) {
- assert_not_zero(proxy_address);
- consumer_proxy_address.write(proxy_address);
- get_latest_round_data();
- return ();
-}
-
-// Get the latest data and store it.
-@external
-func get_latest_round_data{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- round: Round
-) {
- let (proxy: felt) = consumer_proxy_address.read();
- let (round: Round) = IAggregator.latest_round_data(contract_address=proxy);
- feed_data.write(round);
- return (round=round);
-}
-
-@view
-func get_stored_round{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- res: Round
-) {
- let (res) = feed_data.read();
- return (res=res);
-}
-
-@view
-func get_stored_feed_address{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (
- res: felt
-) {
- let (res) = consumer_proxy_address.read();
- return (res=res);
-}
diff --git a/examples/contracts/proxy-consumer/contracts/aggregator_proxy_abi.json b/examples/contracts/proxy-consumer/contracts/aggregator_proxy_abi.json
deleted file mode 100644
index 227ae85..0000000
--- a/examples/contracts/proxy-consumer/contracts/aggregator_proxy_abi.json
+++ /dev/null
@@ -1,451 +0,0 @@
-[
- {
- "members": [
- {
- "name": "round_id",
- "offset": 0,
- "type": "felt"
- },
- {
- "name": "answer",
- "offset": 1,
- "type": "felt"
- },
- {
- "name": "block_num",
- "offset": 2,
- "type": "felt"
- },
- {
- "name": "started_at",
- "offset": 3,
- "type": "felt"
- },
- {
- "name": "updated_at",
- "offset": 4,
- "type": "felt"
- }
- ],
- "name": "Round",
- "size": 5,
- "type": "struct"
- },
- {
- "data": [
- {
- "name": "round_id",
- "type": "felt"
- },
- {
- "name": "answer",
- "type": "felt"
- },
- {
- "name": "transmitter",
- "type": "felt"
- },
- {
- "name": "observation_timestamp",
- "type": "felt"
- },
- {
- "name": "observers",
- "type": "felt"
- },
- {
- "name": "observations_len",
- "type": "felt"
- },
- {
- "name": "observations",
- "type": "felt*"
- },
- {
- "name": "juels_per_fee_coin",
- "type": "felt"
- },
- {
- "name": "gas_price",
- "type": "felt"
- },
- {
- "name": "config_digest",
- "type": "felt"
- },
- {
- "name": "epoch_and_round",
- "type": "felt"
- },
- {
- "name": "reimbursement",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "NewTransmission",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "current",
- "type": "felt"
- },
- {
- "name": "round_id",
- "type": "felt"
- },
- {
- "name": "timestamp",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "AnswerUpdated",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "round_id",
- "type": "felt"
- },
- {
- "name": "started_by",
- "type": "felt"
- },
- {
- "name": "started_at",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "NewRound",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "previousOwner",
- "type": "felt"
- },
- {
- "name": "newOwner",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "OwnershipTransferred",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "from_address",
- "type": "felt"
- },
- {
- "name": "to",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "OwnershipTransferRequested",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "user",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "AddedAccess",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "user",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "RemovedAccess",
- "type": "event"
- },
- {
- "data": [],
- "keys": [],
- "name": "CheckAccessEnabled",
- "type": "event"
- },
- {
- "data": [],
- "keys": [],
- "name": "CheckAccessDisabled",
- "type": "event"
- },
- {
- "inputs": [],
- "name": "owner",
- "outputs": [
- {
- "name": "owner",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "proposed_owner",
- "outputs": [
- {
- "name": "proposed_owner",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "new_owner",
- "type": "felt"
- }
- ],
- "name": "transfer_ownership",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [],
- "name": "accept_ownership",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "user",
- "type": "felt"
- }
- ],
- "name": "add_access",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "user",
- "type": "felt"
- }
- ],
- "name": "remove_access",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [],
- "name": "enable_access_check",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [],
- "name": "disable_access_check",
- "outputs": [],
- "type": "function"
- },
- {
- "data": [
- {
- "name": "current",
- "type": "felt"
- },
- {
- "name": "proposed",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "AggregatorProposed",
- "type": "event"
- },
- {
- "data": [
- {
- "name": "previous",
- "type": "felt"
- },
- {
- "name": "latest",
- "type": "felt"
- }
- ],
- "keys": [],
- "name": "AggregatorConfirmed",
- "type": "event"
- },
- {
- "inputs": [
- {
- "name": "owner",
- "type": "felt"
- },
- {
- "name": "address",
- "type": "felt"
- }
- ],
- "name": "constructor",
- "outputs": [],
- "type": "constructor"
- },
- {
- "inputs": [
- {
- "name": "address",
- "type": "felt"
- }
- ],
- "name": "propose_aggregator",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "address",
- "type": "felt"
- }
- ],
- "name": "confirm_aggregator",
- "outputs": [],
- "type": "function"
- },
- {
- "inputs": [],
- "name": "latest_round_data",
- "outputs": [
- {
- "name": "round",
- "type": "Round"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "round_id",
- "type": "felt"
- }
- ],
- "name": "round_data",
- "outputs": [
- {
- "name": "round",
- "type": "Round"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "proposed_latest_round_data",
- "outputs": [
- {
- "name": "round",
- "type": "Round"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "round_id",
- "type": "felt"
- }
- ],
- "name": "proposed_round_data",
- "outputs": [
- {
- "name": "round",
- "type": "Round"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "aggregator",
- "outputs": [
- {
- "name": "aggregator",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "phase_id",
- "outputs": [
- {
- "name": "phase_id",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "description",
- "outputs": [
- {
- "name": "description",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "decimals",
- "outputs": [
- {
- "name": "decimals",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [],
- "name": "type_and_version",
- "outputs": [
- {
- "name": "meta",
- "type": "felt"
- }
- ],
- "stateMutability": "view",
- "type": "function"
- }
-]
diff --git a/examples/contracts/proxy-consumer/hardhat.config.ts b/examples/contracts/proxy-consumer/hardhat.config.ts
deleted file mode 100644
index 0aea8ea..0000000
--- a/examples/contracts/proxy-consumer/hardhat.config.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { HardhatUserConfig } from 'hardhat/types'
-import '@shardlabs/starknet-hardhat-plugin'
-
-const config: HardhatUserConfig = {
- solidity: '0.8.14',
- starknet: {
- venv: 'active',
- network: 'alphaGoerli',
- wallets: {
- OpenZeppelin: {
- accountName: 'OpenZeppelin',
- modulePath: 'starkware.starknet.wallets.open_zeppelin.OpenZeppelinAccount',
- accountPath: '~/.starknet_accounts',
- },
- },
- },
- paths: {
- cairoPaths: ['../../../contracts/src'],
- },
-}
-
-export default config
diff --git a/examples/contracts/proxy-consumer/package.json b/examples/contracts/proxy-consumer/package.json
deleted file mode 100644
index a447a0f..0000000
--- a/examples/contracts/proxy-consumer/package.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "proxy-consumer",
- "version": "1.0.0",
- "description": "Simple contracts to read Plugin data feeds on-chain and off-chain",
- "scripts": {
- "build": "yarn hardhat starknet-compile",
- "deploy": "yarn ts-node ./scripts/deployConsumer.ts",
- "readLatestRound": "yarn ts-node ./scripts/readLatestRound.ts",
- "readLatestRoundOffChain": "yarn ts-node ./scripts/readLatestRoundOffChain.ts"
- },
- "license": "MIT",
- "devDependencies": {
- "@shardlabs/starknet-hardhat-plugin": "^0.8.0-alpha.0"
- },
- "dependencies": {
- "starknet": "^4.17.1"
- }
-}
diff --git a/examples/contracts/proxy-consumer/scripts/deployConsumer.ts b/examples/contracts/proxy-consumer/scripts/deployConsumer.ts
deleted file mode 100644
index 443bfed..0000000
--- a/examples/contracts/proxy-consumer/scripts/deployConsumer.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import fs from 'fs'
-import { Account, Provider, Contract, json, ec } from 'starknet'
-
-// Starknet network: Either goerli-alpha or mainnet-alpha
-const network = 'goerli-alpha'
-
-// The Cairo contract that is compiled and ready to declare and deploy
-const consumerContractName = 'Proxy_consumer'
-const consumerClassHash = '0x75f25b359402fa046e2b9c17d00138772b51c647c0352eb16954e9e39df4ca6'
-
-/**
- * Network: Starknet Goerli testnet
- * Aggregator: PLI/USD
- * Address: 0x2579940ca3c41e7119283ceb82cd851c906cbb1510908a913d434861fdcb245
- * Find more feed address at:
- * https://docs.chain.link/data-feeds/price-feeds/addresses?network=starknet
- */
-const dataFeedAddress = '0x2579940ca3c41e7119283ceb82cd851c906cbb1510908a913d434861fdcb245'
-
-/** Environment variables for a deployed and funded account to use for deploying contracts
- * Find your OpenZeppelin account address and private key at:
- * ~/.starknet_accounts/starknet_open_zeppelin_accounts.json
- */
-const accountAddress = process.env.DEPLOYER_ACCOUNT_ADDRESS as string
-const accountKeyPair = ec.getKeyPair(process.env.DEPLOYER_PRIVATE_KEY as string)
-
-export async function deployContract() {
- const provider = new Provider({
- sequencer: {
- network: network,
- },
- })
-
- const account = new Account(provider, accountAddress, accountKeyPair)
-
- const consumerContract = json.parse(
- fs
- .readFileSync(
- `${__dirname}/../starknet-artifacts/contracts/${consumerContractName}.cairo/${consumerContractName}.json`,
- )
- .toString('ascii'),
- )
-
- const declareDeployConsumer = await account.declareDeploy({
- contract: consumerContract,
- classHash: consumerClassHash,
- constructorCalldata: [dataFeedAddress as string],
- })
-
- const consumerDeploy = new Contract(
- consumerContract.abi,
- declareDeployConsumer.deploy.contract_address,
- provider,
- )
-
- console.log('Contract address: ' + consumerDeploy.address)
- console.log('Transaction hash: ' + declareDeployConsumer.deploy.transaction_hash)
-}
-
-deployContract()
diff --git a/examples/contracts/proxy-consumer/scripts/readLatestRound.ts b/examples/contracts/proxy-consumer/scripts/readLatestRound.ts
deleted file mode 100644
index 8eff53d..0000000
--- a/examples/contracts/proxy-consumer/scripts/readLatestRound.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import fs from 'fs'
-import { Account, Provider, Contract, CallContractResponse, json, ec } from 'starknet'
-
-// Starknet network: Either goerli-alpha or mainnet-alpha
-const network = 'goerli-alpha'
-
-/** Environment variables for a deployed and funded account to use for deploying contracts
- * Find your OpenZeppelin account address and private key at:
- * ~/.starknet_accounts/starknet_open_zeppelin_accounts.json
- */
-const accountAddress = process.env.DEPLOYER_ACCOUNT_ADDRESS as string
-const accountKeyPair = ec.getKeyPair(process.env.DEPLOYER_PRIVATE_KEY as string)
-
-const consumerContractName = 'Proxy_consumer'
-
-const contractAddress = process.argv.at(2) as string
-
-const provider = new Provider({
- sequencer: {
- network: network,
- },
-})
-
-const account = new Account(provider, accountAddress, accountKeyPair)
-
-export async function updateStoredRound(account: Account, contractAddress: string) {
- const consumerContract = json.parse(
- fs
- .readFileSync(
- `${__dirname}/../starknet-artifacts/contracts/${consumerContractName}.cairo/${consumerContractName}.json`,
- )
- .toString('ascii'),
- )
-
- const targetContract = new Contract(consumerContract.abi, contractAddress, account)
-
- const response = await targetContract.invoke('get_latest_round_data')
-
- console.log('\nInvoking the get_latest_round_data function.')
- console.log('Transaction hash: ' + response.transaction_hash)
-
- console.log('Waiting for transaction...')
- let transactionStatus = (await provider.getTransactionReceipt(response.transaction_hash)).status
- while (transactionStatus !== 'REJECTED' && transactionStatus !== 'ACCEPTED_ON_L2') {
- console.log('Transaction status is: ' + transactionStatus)
- await new Promise((f) => setTimeout(f, 10000))
- transactionStatus = (await provider.getTransactionReceipt(response.transaction_hash)).status
- }
- console.log('Transaction is: ' + transactionStatus)
- readStoredRound(account, contractAddress)
-}
-
-export async function readStoredRound(account: Account, contractAddress: string) {
- const round = await account.callContract({
- contractAddress: contractAddress,
- entrypoint: 'get_stored_round',
- })
-
- console.log('\nStored values are:')
- printResult(round)
- return round
-}
-
-export async function readStoredProxy(account: Account, contractAddress: string) {
- const feed = await account.callContract({
- contractAddress: contractAddress,
- entrypoint: 'get_stored_feed_address',
- })
-
- return feed
-}
-
-function printResult(latestRound: CallContractResponse) {
- console.log('round_id =', parseInt(latestRound.result[0], 16))
- console.log('answer =', parseInt(latestRound.result[1], 16))
- console.log('block_num =', parseInt(latestRound.result[2], 16))
- console.log('observation_timestamp =', parseInt(latestRound.result[3], 16))
- console.log('transmission_timestamp =', parseInt(latestRound.result[4], 16))
-}
-
-updateStoredRound(account, contractAddress)
diff --git a/examples/contracts/proxy-consumer/scripts/readLatestRoundOffChain.ts b/examples/contracts/proxy-consumer/scripts/readLatestRoundOffChain.ts
deleted file mode 100644
index 8682950..0000000
--- a/examples/contracts/proxy-consumer/scripts/readLatestRoundOffChain.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Provider, CallContractResponse } from 'starknet'
-
-// Starknet network: Either goerli-alpha or mainnet-alpha
-const network = 'goerli-alpha'
-
-/**
- * Network: Starknet Goerli testnet
- * Aggregator: PLI/USD
- * Address: 0x2579940ca3c41e7119283ceb82cd851c906cbb1510908a913d434861fdcb245
- * Find more proxy address at:
- * https://docs.chain.link/data-feeds/price-feeds/addresses?network=starknet
- */
-const dataFeedAddress = '0x2579940ca3c41e7119283ceb82cd851c906cbb1510908a913d434861fdcb245'
-
-export async function readLatestRoundOffChain() {
- const provider = new Provider({
- sequencer: {
- network: network,
- },
- })
-
- const latestRound = await provider.callContract({
- contractAddress: dataFeedAddress,
- entrypoint: 'latest_round_data',
- })
-
- printResult(latestRound)
- return latestRound
-}
-
-function printResult(latestRound: CallContractResponse) {
- console.log('round_id =', parseInt(latestRound.result[0], 16))
- console.log('answer =', parseInt(latestRound.result[1], 16))
- console.log('block_num =', parseInt(latestRound.result[2], 16))
- console.log('observation_timestamp =', parseInt(latestRound.result[3], 16))
- console.log('transmission_timestamp =', parseInt(latestRound.result[4], 16))
-}
-
-readLatestRoundOffChain()
diff --git a/flake.lock b/flake.lock
index 575dc60..83b94c0 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,12 +1,15 @@
{
"nodes": {
"flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
"locked": {
- "lastModified": 1678901627,
- "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
+ "lastModified": 1710146030,
+ "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
+ "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@@ -17,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1678898370,
- "narHash": "sha256-xTICr1j+uat5hk9FyuPOFGxpWHdJRibwZC+ATi0RbtE=",
+ "lastModified": 1723991338,
+ "narHash": "sha256-Grh5PF0+gootJfOJFenTTxDTYPidA3V28dqJ/WV7iis=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "ac718d02867a84b42522a0ece52d841188208f2c",
+ "rev": "8a3354191c0d7144db9756a74755672387b702ba",
"type": "github"
},
"original": {
@@ -31,10 +34,60 @@
"type": "github"
}
},
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1718428119,
+ "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
"root": {
"inputs": {
"flake-utils": "flake-utils",
- "nixpkgs": "nixpkgs"
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "nixpkgs": "nixpkgs_2"
+ },
+ "locked": {
+ "lastModified": 1724206841,
+ "narHash": "sha256-L8dKaX4T3k+TR2fEHCfGbH4UXdspovz/pj87iai9qmc=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "45e98fbd62c32e5927e952d2833fa1ba4fb35a61",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
}
}
},
diff --git a/flake.nix b/flake.nix
index f8c2d49..e9f27e5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -4,13 +4,43 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
+ rust-overlay.url = "github:oxalica/rust-overlay";
};
- outputs = inputs@{ self, nixpkgs, flake-utils, ... }:
- flake-utils.lib.eachDefaultSystem (system:
+ outputs = inputs@{ self, nixpkgs, flake-utils, rust-overlay, ... }:
+ flake-utils.lib.eachDefaultSystem (system:
let
- pkgs = import nixpkgs { inherit system; overlays = [ ]; };
- in rec {
- devShell = pkgs.callPackage ./shell.nix {};
+ pkgs = import nixpkgs { inherit system; overlays = [ rust-overlay.overlays.default ]; };
+ in
+ {
+ devShell = pkgs.callPackage ./shell.nix {
+ inherit pkgs;
+ scriptDir = toString ./.; # This converts the flake's root directory to a string
+ };
+
+ packages = {
+ starknet-devnet = pkgs.stdenv.mkDerivation rec {
+ name = "starknet-devnet";
+ src = ./ops/scripts;
+ installPhase = ''
+ mkdir -p $out/bin
+ cp $src/devnet-hardhat.sh $out/bin/${name}
+ cp $src/devnet-hardhat-down.sh $out/bin/
+ chmod +x $out/bin/${name}
+ '';
+ };
+
+ starknet-devnet-down = pkgs.stdenv.mkDerivation rec {
+ name = "starknet-devnet-down";
+ src = ./ops/scripts;
+ installPhase = ''
+ mkdir -p $out/bin
+ cp $src/devnet-hardhat-down.sh $out/bin/${name}
+ chmod +x $out/bin/${name}
+ '';
+ };
+ };
+
+ formatter = pkgs.nixpkgs-fmt;
});
}
diff --git a/contracts/constraints.txt b/integration-tests/.root_dir
similarity index 100%
rename from contracts/constraints.txt
rename to integration-tests/.root_dir
diff --git a/integration-tests/.sample.env b/integration-tests/.sample.env
new file mode 100644
index 0000000..d35bb22
--- /dev/null
+++ b/integration-tests/.sample.env
@@ -0,0 +1,24 @@
+
+# Starknet settings
+export ACCOUNT=
+export PRIVATE_KEY=
+export NODE_COUNT=5
+export TTL=1h
+export L2_RPC_URL= # https://alpha4.starknet.io
+
+# Test Settings
+export KEEP_ENVIRONMENTS="Never" # Always | OnFail | Never
+export PLUGIN_IMAGE="public.ecr.aws/plugin/plugin" # Image repo to pull the Plugin image from
+export PLUGIN_VERSION="1.13.0" # Version of the Plugin image to pull
+export PLUGIN_ENV_USER="Satoshi-Nakamoto" # Name of the person running the tests (change to your own)
+export TEST_LOG_LEVEL="info" # info | debug | trace
+
+# Soak/Chaos/Load Test Specific Settings
+export ENV_JOB_IMAGE="image-location/plugin-tests:test-tag" # Image repo to pull the remote-test-runner image from. Check the Integration Tests workflow.
+export DETACH_RUNNER="true" # true 99% of the time, false if you are debugging soak test issues
+export TEST_SUITE="soak" # soak | chaos | load
+
+# Slack Notification Settings
+export SLACK_API_KEY="xoxb-example-key" # API key used to report soak test results to slack
+export SLACK_CHANNEL="C000000000" # Channel ID for the slack bot to post test results
+export SLACK_USER="U000000000" # User ID of the person running the soak tests to properly notify them
\ No newline at end of file
diff --git a/integration-tests/README.md b/integration-tests/README.md
index 55c623e..f32a644 100644
--- a/integration-tests/README.md
+++ b/integration-tests/README.md
@@ -1,7 +1,52 @@
-# Local k8s run
+## Integration tests - HOWTO
-See [there](../docs/integration-tests/README.md)
+### Prerequisites
+1. `cd contracts && scarb --profile release build`
+2. `yarn install`
+3. `yarn build`
+
+#### TOML preparation
+The integration tests are using TOML as the configuration input. The logic and parsing is located under [Test config](./testconfig)
+
+By default, the tests will be running with the default config set in [default.toml](./testconfig/default.toml). This configuration is set to run on devnet with local docker.
+
+Fields in the default toml can be overriden by creating an `overrides.toml`file. Any values specified here take precedence and will be overwritten if they overlap with `default.toml`.
+
+##### Testnet runs
+In order to run the tests on Testnet, additional variables need to be specified in the TOML, these would also be pointed out if `network = "testnet"` is set. The additional variables are:
+
+- `l2_rpc_url` - L2 RPC url
+- `account` - Account address on L2
+- `private_key` - Private key for L2 account
+
+##### Running in k8s
+
+Set `inside_k8 = true` under `[Common]`.
+
+#### Run smoke tests
+
+`cd integration-tests && go test --timeout=2h -v -count=1 -json ./smoke`
+
+
+### On demand soak test
+
+Navigate to the [workflow](https://github.com/goplugin/plugin-starknet/actions/workflows/integration-tests-soak.yml). The workflow takes in 3 parameters:
+
+- Base64 string of the .toml configuration
+- Core image tag which defaults to develop
+- Test runner tag, only tag needs to be supplied
+
+Create an `overrides.toml` file in `integration-tests/testconfig` and run `cat overrides.toml | base64`. `inside_k8` needs to be set to true in the .toml in order to run the tests in kubernetes.
+
+#### Local
+
+If you want to kick off the test from local:
+
+- `export TEST_SUITE: soak`
+- `export DETACH_RUNNER: true`
+- `export ENV_JOB_IMAGE: /plugin-solana-tests:`
+- Base64 the .toml config
+- Run `export BASE64_CONFIG_OVERRIDE=""`
+- `cd integration-tests/soak && go test -timeout 24h -count=1 -run TestOCRBasicSoak/embedded -test.timeout 30m;`
-# Integration Tests
-For more information, see the [Plugin Starknet Documentation | Integration Tests](../docs/integration-tests).
diff --git a/integration-tests/common/common.go b/integration-tests/common/common.go
index 3ffc023..6793f1e 100644
--- a/integration-tests/common/common.go
+++ b/integration-tests/common/common.go
@@ -3,136 +3,225 @@ package common
import (
"fmt"
"os"
+ "os/exec"
"strconv"
"strings"
"testing"
"time"
- "github.com/dontpanicdao/caigo/gateway"
+ "github.com/google/uuid"
"github.com/lib/pq"
"github.com/rs/zerolog/log"
- uuid "github.com/satori/go.uuid"
+ "github.com/stretchr/testify/require"
"gopkg.in/guregu/null.v4"
- "github.com/goplugin/plugin-env/environment"
- "github.com/goplugin/plugin-env/pkg/alias"
- "github.com/goplugin/plugin-env/pkg/helm/plugin"
- "github.com/goplugin/plugin-env/pkg/helm/mockserver"
- mockservercfg "github.com/goplugin/plugin-env/pkg/helm/mockserver-cfg"
- "github.com/goplugin/plugin-starknet/ops/devnet"
+ ctfconfig "github.com/goplugin/plugin-testing-framework/config"
+ "github.com/goplugin/plugin-testing-framework/k8s/environment"
+ "github.com/goplugin/plugin-testing-framework/k8s/pkg/helm/plugin"
+ mock_adapter "github.com/goplugin/plugin-testing-framework/k8s/pkg/helm/mock-adapter"
"github.com/goplugin/pluginv3.0/integration-tests/client"
+ "github.com/goplugin/pluginv3.0/integration-tests/docker/test_env"
"github.com/goplugin/pluginv3.0/v2/core/services/job"
- "github.com/goplugin/pluginv3.0/v2/core/services/relay"
-)
-var (
- serviceKeyL1 = "Hardhat"
- serviceKeyL2 = "starknet-dev"
- serviceKeyPlugin = "plugin"
- chainName = "starknet"
- chainId = gateway.GOERLI_ID
+ chainconfig "github.com/goplugin/plugin-starknet/integration-tests/config"
+ "github.com/goplugin/plugin-starknet/integration-tests/testconfig"
+ "github.com/goplugin/plugin-starknet/ops/devnet"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/starknet"
)
type Common struct {
+ ChainDetails *chainconfig.Config
+ TestEnvDetails *TestEnvDetails
+ Env *environment.Environment
+ RPCDetails *RPCDetails
+ PluginConfig string
+ TestConfig *testconfig.TestConfig
+}
+
+type TestEnvDetails struct {
+ TestDuration time.Duration
+ K8Config *environment.Config
+ NodeOpts []test_env.ClNodeOption
+}
+
+type RPCDetails struct {
+ RPCL1Internal string
+ RPCL2Internal string
+ RPCL2InternalAPIKey string
+ RPCL1External string
+ RPCL2External string
+ MockServerURL string
+ MockServerEndpoint string
P2PPort string
- ServiceKeyL1 string
- ServiceKeyL2 string
- ServiceKeyPlugin string
- ChainName string
- ChainId string
- NodeCount int
- TTL time.Duration
- Testnet bool
- L2RPCUrl string
- PrivateKey string
- Account string
- ClConfig map[string]interface{}
- K8Config *environment.Config
- Env *environment.Environment
}
-func New() *Common {
- var err error
- c := &Common{
- ChainName: chainName,
- ChainId: chainId,
- ServiceKeyPlugin: serviceKeyPlugin,
- ServiceKeyL1: serviceKeyL1,
- ServiceKeyL2: serviceKeyL2,
+func New(testConfig *testconfig.TestConfig) *Common {
+ var c *Common
+ chainDetails := chainconfig.DevnetConfig()
+
+ duration, err := time.ParseDuration(*testConfig.OCR2.TestDuration)
+ if err != nil {
+ panic("Invalid test duration")
}
- // Checking if count of OCR nodes is defined in ENV
- nodeCountSet := getEnv("NODE_COUNT")
- if nodeCountSet != "" {
- c.NodeCount, err = strconv.Atoi(nodeCountSet)
- if err != nil {
- panic(fmt.Sprintf("Please define a proper node count for the test: %v", err))
+
+ if *testConfig.Common.Network == "testnet" {
+ chainDetails = chainconfig.SepoliaConfig()
+ chainDetails.L2RPCInternal = *testConfig.Common.L2RPCUrl
+ if testConfig.Common.L2RPCApiKey == nil {
+ chainDetails.L2RPCInternalAPIKey = ""
+ } else {
+ chainDetails.L2RPCInternalAPIKey = *testConfig.Common.L2RPCApiKey
}
} else {
- panic("Please define NODE_COUNT")
+ // set up mocked local feedernet server because starknet-devnet does not provide one
+ localDevnetFeederSrv := starknet.NewTestFeederServer()
+ chainDetails.FeederURL = localDevnetFeederSrv.URL
}
- // Checking if TTL env var is set in ENV
- ttlValue := getEnv("TTL")
- if ttlValue != "" {
- duration, err := time.ParseDuration(ttlValue)
+ c = &Common{
+ TestConfig: testConfig,
+ ChainDetails: chainDetails,
+ TestEnvDetails: &TestEnvDetails{
+ TestDuration: duration,
+ },
+ RPCDetails: &RPCDetails{
+ P2PPort: "6690",
+ RPCL2Internal: chainDetails.L2RPCInternal,
+ RPCL2InternalAPIKey: chainDetails.L2RPCInternalAPIKey,
+ },
+ }
+ // provide getters for TestConfig (pointers to chain + rpc details)
+ c.TestConfig.GetChainID = func() string { return c.ChainDetails.ChainID }
+ c.TestConfig.GetFeederURL = func() string { return c.ChainDetails.FeederURL }
+ c.TestConfig.GetRPCL2Internal = func() string { return c.RPCDetails.RPCL2Internal }
+ c.TestConfig.GetRPCL2InternalAPIKey = func() string { return c.RPCDetails.RPCL2InternalAPIKey }
+
+ return c
+}
+
+func (c *Common) Default(t *testing.T, namespacePrefix string) (*Common, error) {
+ c.TestEnvDetails.K8Config = &environment.Config{
+ NamespacePrefix: fmt.Sprintf("starknet-%s", namespacePrefix),
+ TTL: c.TestEnvDetails.TestDuration,
+ Test: t,
+ }
+
+ if *c.TestConfig.Common.InsideK8s {
+ tomlString, err := c.TestConfig.GetNodeConfigTOML()
if err != nil {
- panic(fmt.Sprintf("Please define a proper duration for the test: %v", err))
+ return nil, err
}
- c.TTL, err = time.ParseDuration(*alias.ShortDur(duration))
- if err != nil {
- panic(fmt.Sprintf("Please define a proper duration for the test: %v", err))
+ var overrideFn = func(_ interface{}, target interface{}) {
+ ctfconfig.MustConfigOverridePluginVersion(c.TestConfig.PluginImage, target)
}
- } else {
- panic("Please define TTL of env")
+ cd := plugin.NewWithOverride(0, map[string]any{
+ "toml": tomlString,
+ "replicas": *c.TestConfig.OCR2.NodeCount,
+ "plugin": map[string]interface{}{
+ "resources": map[string]interface{}{
+ "requests": map[string]interface{}{
+ "cpu": "2000m",
+ "memory": "4Gi",
+ },
+ "limits": map[string]interface{}{
+ "cpu": "2000m",
+ "memory": "4Gi",
+ },
+ },
+ },
+ "db": map[string]any{
+ "image": map[string]any{
+ "version": *c.TestConfig.Common.PostgresVersion,
+ },
+ "stateful": c.TestConfig.Common.Stateful,
+ },
+ }, c.TestConfig.PluginImage, overrideFn)
+ c.Env = environment.New(c.TestEnvDetails.K8Config).
+ AddHelm(devnet.New(nil)).
+ AddHelm(mock_adapter.New(nil)).
+ AddHelm(cd)
}
- // Setting optional parameters
- c.L2RPCUrl = getEnv("L2_RPC_URL") // Fetch L2 RPC url if defined
- c.Testnet = c.L2RPCUrl != ""
- c.PrivateKey = getEnv("PRIVATE_KEY")
- c.Account = getEnv("ACCOUNT")
-
- return c
+ return c, nil
}
-// getEnv gets the environment variable if it exists and sets it for the remote runner
-func getEnv(v string) string {
- val := os.Getenv(v)
- if val != "" {
- os.Setenv(fmt.Sprintf("TEST_%s", v), val)
+func (c *Common) SetLocalEnvironment(t *testing.T) {
+ // Run scripts to set up local test environment
+ log.Info().Msg("Starting starknet-devnet container...")
+ err := exec.Command("../../scripts/devnet.sh").Run()
+ require.NoError(t, err, "Could not start devnet container")
+ // TODO: add hardhat too
+ log.Info().Msg("Starting postgres container...")
+ err = exec.Command("../../scripts/postgres.sh").Run()
+ require.NoError(t, err, "Could not start postgres container")
+ log.Info().Msg("Starting mock adapter...")
+ err = exec.Command("../../scripts/mock-adapter.sh").Run()
+ require.NoError(t, err, "Could not start mock adapter")
+ log.Info().Msg("Starting core nodes...")
+ cmd := exec.Command("../../scripts/core.sh")
+ cmd.Env = append(os.Environ(), fmt.Sprintf("CL_CONFIG=%s", c.PluginConfig))
+ err = cmd.Run()
+ require.NoError(t, err, "Could not start core nodes")
+ log.Info().Msg("Set up local stack complete.")
+
+ // Set PluginNodeDetails
+ var nodeDetails []*environment.PluginNodeDetail
+ var basePort = 50100
+ for i := 0; i < *c.TestConfig.OCR2.NodeCount; i++ {
+ dbLocalIP := fmt.Sprintf("postgresql://postgres:postgres@plugin.postgres:5432/starknet_test_%d?sslmode=disable", i+1)
+ nodeDetails = append(nodeDetails, &environment.PluginNodeDetail{
+ ChartName: "unused",
+ PodName: "unused",
+ LocalIP: "http://127.0.0.1:" + strconv.Itoa(basePort+i),
+ // InternalIP: "http://host.container.internal:" + strconv.Itoa(basePort+i), // TODO: plugin.core.${i}:6688
+ InternalIP: fmt.Sprintf("http://plugin.core.%d:6688", i+1), // TODO: plugin.core.1:6688
+ DBLocalIP: dbLocalIP,
+ })
}
- return val
+ c.Env.PluginNodeDetails = nodeDetails
}
-// CreateKeys Creates node keys and defines chain and nodes for each node
-func (c *Common) CreateKeys(env *environment.Environment) ([]client.NodeKeysBundle, []*client.Plugin, error) {
- PluginNodes, err := client.ConnectPluginNodes(env)
- if err != nil {
- return nil, nil, err
- }
- NKeys, _, err := client.CreateNodeKeysBundle(PluginNodes, c.ChainName, c.ChainId)
- if err != nil {
- return nil, nil, err
- }
- for _, n := range PluginNodes {
- _, _, err = n.CreateStarkNetChain(&client.StarkNetChainAttributes{
- Type: c.ChainName,
- ChainID: c.ChainId,
- Config: client.StarkNetChainConfig{},
- })
+func (c *Common) TearDownLocalEnvironment(t *testing.T) {
+ log.Info().Msg("Tearing down core nodes...")
+ err := exec.Command("../../scripts/core.down.sh").Run()
+ require.NoError(t, err, "Could not tear down core nodes")
+ log.Info().Msg("Tearing down mock adapter...")
+ err = exec.Command("../../scripts/mock-adapter.down.sh").Run()
+ require.NoError(t, err, "Could not tear down mock adapter")
+ log.Info().Msg("Tearing down postgres container...")
+ err = exec.Command("../../scripts/postgres.down.sh").Run()
+ require.NoError(t, err, "Could not tear down postgres container")
+ log.Info().Msg("Tearing down devnet container...")
+ err = exec.Command("../../scripts/devnet.down.sh").Run()
+ require.NoError(t, err, "Could not tear down devnet container")
+ log.Info().Msg("Tear down local stack complete.")
+}
+
+func (c *Common) CreateNodeKeysBundle(nodes []*client.PluginClient) ([]client.NodeKeysBundle, error) {
+ nkb := make([]client.NodeKeysBundle, 0)
+ for _, n := range nodes {
+ p2pkeys, err := n.MustReadP2PKeys()
if err != nil {
- return nil, nil, err
+ return nil, err
}
- _, _, err = n.CreateStarkNetNode(&client.StarkNetNodeAttributes{
- Name: c.ChainName,
- ChainID: c.ChainId,
- Url: env.URLs[c.ServiceKeyL2][1],
- })
+
+ peerID := p2pkeys.Data[0].Attributes.PeerID
+ txKey, _, err := n.CreateTxKey(c.ChainDetails.ChainName, c.ChainDetails.ChainID)
if err != nil {
- return nil, nil, err
+ return nil, err
}
+ ocrKey, _, err := n.CreateOCR2Key(c.ChainDetails.ChainName)
+ if err != nil {
+ return nil, err
+ }
+
+ nkb = append(nkb, client.NodeKeysBundle{
+ PeerID: peerID,
+ OCR2Key: *ocrKey,
+ TXKey: *txKey,
+ })
}
- return NKeys, PluginNodes, nil
+ return nkb, nil
}
// CreateJobsForContract Creates and sets up the boostrap jobs as well as OCR jobs
@@ -140,32 +229,31 @@ func (c *Common) CreateJobsForContract(cc *PluginClient, observationSource strin
// Define node[0] as bootstrap node
cc.bootstrapPeers = []client.P2PData{
{
- RemoteIP: cc.PluginNodes[0].RemoteIP(),
- RemotePort: c.P2PPort,
- PeerID: cc.NKeys[0].PeerID,
+ InternalIP: cc.PluginNodes[0].InternalIP(),
+ InternalPort: c.RPCDetails.P2PPort,
+ PeerID: cc.NKeys[0].PeerID,
},
}
// Defining relay config
bootstrapRelayConfig := job.JSONConfig{
- "nodeName": fmt.Sprintf("\"starknet-OCRv2-%s-%s\"", "node", uuid.NewV4().String()),
- "accountAddress": fmt.Sprintf("\"%s\"", accountAddresses[0]),
- "chainID": fmt.Sprintf("\"%s\"", c.ChainId),
+ "nodeName": fmt.Sprintf("starknet-OCRv2-%s-%s", "node", uuid.New().String()),
+ "accountAddress": accountAddresses[0],
+ "chainID": c.ChainDetails.ChainID,
}
oracleSpec := job.OCR2OracleSpec{
ContractID: ocrControllerAddress,
- Relay: relay.StarkNet,
+ Relay: c.ChainDetails.ChainName,
RelayConfig: bootstrapRelayConfig,
ContractConfigConfirmations: 1, // don't wait for confirmation on devnet
}
// Setting up bootstrap node
jobSpec := &client.OCR2TaskJobSpec{
- Name: fmt.Sprintf("starknet-OCRv2-%s-%s", "bootstrap", uuid.NewV4().String()),
+ Name: fmt.Sprintf("starknet-OCRv2-%s-%s", "bootstrap", uuid.New().String()),
JobType: "bootstrap",
OCR2OracleSpec: oracleSpec,
}
-
_, _, err := cc.PluginNodes[0].CreateJob(jobSpec)
if err != nil {
return err
@@ -177,24 +265,29 @@ func (c *Common) CreateJobsForContract(cc *PluginClient, observationSource strin
p2pBootstrappers = append(p2pBootstrappers, cc.bootstrapPeers[i].P2PV2Bootstrapper())
}
+ sourceValueBridge := &client.BridgeTypeAttributes{
+ Name: "mockserver-bridge",
+ URL: c.RPCDetails.MockServerEndpoint + "/" + strings.TrimPrefix(c.RPCDetails.MockServerURL, "/"),
+ }
+
// Setting up job specs
for nIdx, n := range cc.PluginNodes {
if nIdx == 0 {
continue
}
- _, err := n.CreateBridge(cc.bTypeAttr)
+ err := n.MustCreateBridge(sourceValueBridge)
if err != nil {
return err
}
relayConfig := job.JSONConfig{
"nodeName": bootstrapRelayConfig["nodeName"],
- "accountAddress": fmt.Sprintf("\"%s\"", accountAddresses[nIdx]),
+ "accountAddress": accountAddresses[nIdx],
"chainID": bootstrapRelayConfig["chainID"],
}
oracleSpec = job.OCR2OracleSpec{
ContractID: ocrControllerAddress,
- Relay: relay.StarkNet,
+ Relay: c.ChainDetails.ChainName,
RelayConfig: relayConfig,
PluginType: "median",
OCRKeyBundleID: null.StringFrom(cc.NKeys[nIdx].OCR2Key.Data.ID),
@@ -207,50 +300,15 @@ func (c *Common) CreateJobsForContract(cc *PluginClient, observationSource strin
}
jobSpec = &client.OCR2TaskJobSpec{
- Name: fmt.Sprintf("starknet-OCRv2-%d-%s", nIdx, uuid.NewV4().String()),
+ Name: fmt.Sprintf("starknet-OCRv2-%d-%s", nIdx, uuid.New().String()),
JobType: "offchainreporting2",
OCR2OracleSpec: oracleSpec,
ObservationSource: observationSource,
}
- _, _, err = n.CreateJob(jobSpec)
+ _, err = n.MustCreateJob(jobSpec)
if err != nil {
return err
}
}
return nil
}
-
-func (c *Common) Default(t *testing.T) {
- c.K8Config = &environment.Config{NamespacePrefix: "plugin-ocr-starknet", TTL: c.TTL, Test: t}
- starknetUrl := fmt.Sprintf("http://%s:%d", serviceKeyL2, 5000)
- if c.Testnet {
- starknetUrl = c.L2RPCUrl
- }
- baseTOML := fmt.Sprintf(`[[Starknet]]
-Enabled = true
-ChainID = '%s'
-[[Starknet.Nodes]]
-Name = 'primary'
-URL = '%s'
-
-[OCR2]
-Enabled = true
-
-[P2P]
-[P2P.V2]
-Enabled = true
-DeltaDial = '5s'
-DeltaReconcile = '5s'
-ListenAddresses = ['0.0.0.0:6690']
-`, c.ChainId, starknetUrl)
- log.Debug().Str("toml", baseTOML).Msg("TOML")
- c.ClConfig = map[string]interface{}{
- "replicas": c.NodeCount,
- "toml": baseTOML,
- }
- c.Env = environment.New(c.K8Config).
- AddHelm(devnet.New(nil)).
- AddHelm(mockservercfg.New(nil)).
- AddHelm(mockserver.New(nil)).
- AddHelm(plugin.New(0, c.ClConfig))
-}
diff --git a/integration-tests/common/gauntlet_common.go b/integration-tests/common/gauntlet_common.go
index 35ce6a6..f40fea6 100644
--- a/integration-tests/common/gauntlet_common.go
+++ b/integration-tests/common/gauntlet_common.go
@@ -9,78 +9,83 @@ import (
"github.com/goplugin/plugin-starknet/integration-tests/utils"
)
-var (
- ethAddressGoerli = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
- nAccount string
-)
-
-func (testState *Test) fundNodes() ([]string, error) {
- l := utils.GetTestLogger(testState.T)
+func (m *OCRv2TestState) fundNodes() ([]string, error) {
+ l := utils.GetTestLogger(m.TestConfig.T)
var nAccounts []string
- var err error
- for _, key := range testState.GetNodeKeys() {
+ for _, key := range m.GetNodeKeys() {
if key.TXKey.Data.Attributes.StarkKey == "" {
return nil, errors.New("stark key can't be empty")
}
- nAccount, err = testState.Sg.DeployAccountContract(100, key.TXKey.Data.Attributes.StarkKey)
+ nAccount, err := m.Clients.GauntletClient.DeployAccountContract(100, key.TXKey.Data.Attributes.StarkKey)
if err != nil {
return nil, err
}
nAccounts = append(nAccounts, nAccount)
}
- if err != nil {
- return nil, err
- }
-
- if testState.Common.Testnet {
+ if *m.Common.TestConfig.Common.Network == "testnet" {
for _, key := range nAccounts {
// We are not deploying in parallel here due to testnet limitations (429 too many requests)
l.Debug().Msg(fmt.Sprintf("Funding node with address: %s", key))
- _, err = testState.Sg.TransferToken(ethAddressGoerli, key, "100000000000000000") // Transferring 1 ETH to each node
+ _, err := m.Clients.GauntletClient.TransferToken(m.Common.ChainDetails.StarkTokenAddress, key, "10000000000000000000") // Transferring 10 STRK to each node
if err != nil {
return nil, err
}
}
-
} else {
- err = testState.Devnet.FundAccounts(nAccounts)
- if err != nil {
- return nil, err
+ // The starknet provided mint method does not work so we send a req directly
+ for _, key := range nAccounts {
+ res, err := m.TestConfig.Resty.R().SetBody(map[string]any{
+ "address": key,
+ "amount": 900000000000000000,
+ }).Post("/mint")
+ if err != nil {
+ return nil, err
+ }
+ l.Info().Msg(fmt.Sprintf("Funding account (WEI): %s", string(res.Body())))
+ res, err = m.TestConfig.Resty.R().SetBody(map[string]any{
+ "address": key,
+ "amount": 900000000000000000,
+ "unit": m.Common.ChainDetails.TokenName,
+ }).Post("/mint")
+ if err != nil {
+ return nil, err
+ }
+ l.Info().Msg(fmt.Sprintf("Funding account (FRI): %s", string(res.Body())))
}
}
return nAccounts, nil
}
-func (testState *Test) deployLinkToken() error {
+func (m *OCRv2TestState) deployLinkToken() error {
var err error
- testState.LinkTokenAddr, err = testState.Sg.DeployLinkTokenContract()
+ m.Contracts.LinkTokenAddr, err = m.Clients.GauntletClient.DeployLinkTokenContract()
if err != nil {
return err
}
- err = os.Setenv("PLI", testState.LinkTokenAddr)
+ err = os.Setenv("PLI", m.Contracts.LinkTokenAddr)
if err != nil {
return err
}
return nil
}
-func (testState *Test) deployAccessController() error {
+func (m *OCRv2TestState) deployAccessController() error {
var err error
- testState.AccessControllerAddr, err = testState.Sg.DeployAccessControllerContract()
+ m.Contracts.AccessControllerAddr, err = m.Clients.GauntletClient.DeployAccessControllerContract()
if err != nil {
return err
}
- err = os.Setenv("BILLING_ACCESS_CONTROLLER", testState.AccessControllerAddr)
+ err = os.Setenv("BILLING_ACCESS_CONTROLLER", m.Contracts.AccessControllerAddr)
if err != nil {
return err
}
return nil
}
-func (testState *Test) setConfigDetails(ocrAddress string) error {
- cfg, err := testState.LoadOCR2Config()
+func (m *OCRv2TestState) setConfigDetails(ocrAddress string) error {
+ cfg, err := m.LoadOCR2Config()
if err != nil {
return err
}
@@ -89,54 +94,54 @@ func (testState *Test) setConfigDetails(ocrAddress string) error {
if err != nil {
return err
}
- _, err = testState.Sg.SetConfigDetails(string(parsedConfig), ocrAddress)
+ _, err = m.Clients.GauntletClient.SetConfigDetails(string(parsedConfig), ocrAddress)
return err
}
-func (testState *Test) DeployGauntlet(minSubmissionValue int64, maxSubmissionValue int64, decimals int, name string, observationPaymentGjuels int64, transmissionPaymentGjuels int64) error {
- err := testState.Sg.InstallDependencies()
+func (m *OCRv2TestState) DeployGauntlet(minSubmissionValue int64, maxSubmissionValue int64, decimals int, name string, observationPaymentGjuels int64, transmissionPaymentGjuels int64) error {
+ err := m.Clients.GauntletClient.InstallDependencies()
if err != nil {
return err
}
- testState.AccountAddresses, err = testState.fundNodes()
+ m.Clients.PluginClient.AccountAddresses, err = m.fundNodes()
if err != nil {
return err
}
- err = testState.deployLinkToken()
+ err = m.deployLinkToken()
if err != nil {
return err
}
- err = testState.deployAccessController()
+ err = m.deployAccessController()
if err != nil {
return err
}
- testState.OCRAddr, err = testState.Sg.DeployOCR2ControllerContract(minSubmissionValue, maxSubmissionValue, decimals, name, testState.LinkTokenAddr)
+ m.Contracts.OCRAddr, err = m.Clients.GauntletClient.DeployOCR2ControllerContract(minSubmissionValue, maxSubmissionValue, decimals, name, m.Contracts.LinkTokenAddr)
if err != nil {
return err
}
- testState.ProxyAddr, err = testState.Sg.DeployOCR2ProxyContract(testState.OCRAddr)
+ m.Contracts.ProxyAddr, err = m.Clients.GauntletClient.DeployOCR2ProxyContract(m.Contracts.OCRAddr)
if err != nil {
return err
}
- _, err = testState.Sg.AddAccess(testState.OCRAddr, testState.ProxyAddr)
+ _, err = m.Clients.GauntletClient.AddAccess(m.Contracts.OCRAddr, m.Contracts.ProxyAddr)
if err != nil {
return err
}
- _, err = testState.Sg.MintLinkToken(testState.LinkTokenAddr, testState.OCRAddr, "100000000000000000000")
+ _, err = m.Clients.GauntletClient.MintLinkToken(m.Contracts.LinkTokenAddr, m.Contracts.OCRAddr, "100000000000000000000")
if err != nil {
return err
}
- _, err = testState.Sg.SetOCRBilling(observationPaymentGjuels, transmissionPaymentGjuels, testState.OCRAddr)
+ _, err = m.Clients.GauntletClient.SetOCRBilling(observationPaymentGjuels, transmissionPaymentGjuels, m.Contracts.OCRAddr)
if err != nil {
return err
}
- err = testState.setConfigDetails(testState.OCRAddr)
+ err = m.setConfigDetails(m.Contracts.OCRAddr)
return err
}
diff --git a/integration-tests/common/test_common.go b/integration-tests/common/test_common.go
index 1e32e73..a8f7bb6 100644
--- a/integration-tests/common/test_common.go
+++ b/integration-tests/common/test_common.go
@@ -2,144 +2,251 @@ package common
import (
"context"
- "encoding/hex"
"fmt"
"math/big"
- "os"
- "strings"
+ "net/http"
"testing"
"time"
- caigotypes "github.com/dontpanicdao/caigo/types"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetdevnet "github.com/NethermindEth/starknet.go/devnet"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ "github.com/go-resty/resty/v2"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "github.com/goplugin/plugin-relay/pkg/logger"
- "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
- "github.com/goplugin/plugin-starknet/relayer/pkg/starknet"
+ "github.com/goplugin/plugin-common/pkg/logger"
+ test_env_ctf "github.com/goplugin/plugin-testing-framework/docker/test_env"
+ "github.com/goplugin/plugin-testing-framework/logging"
+ "github.com/goplugin/pluginv3.0/integration-tests/client"
+ "github.com/goplugin/pluginv3.0/integration-tests/docker/test_env"
+
+ test_env_starknet "github.com/goplugin/plugin-starknet/integration-tests/docker/testenv"
+ "github.com/goplugin/plugin-starknet/integration-tests/testconfig"
"github.com/goplugin/plugin-starknet/ops"
- "github.com/goplugin/plugin-starknet/ops/devnet"
"github.com/goplugin/plugin-starknet/ops/gauntlet"
- "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/keys"
- ctfClient "github.com/goplugin/plugin-testing-framework/client"
- "github.com/goplugin/pluginv3.0/integration-tests/client"
-
- "github.com/goplugin/plugin-starknet/integration-tests/utils"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/starknet"
)
var (
- // These are one of the default addresses based on the seed we pass to devnet which is 0
- defaultWalletPrivKey = ops.PrivateKeys0Seed[0]
- defaultWalletAddress string // derived in init()
- rpcRequestTimeout = time.Second * 300
- dumpPath = "/dumps/dump.pkl"
- mockServerValue = 900000
+ rpcRequestTimeout = time.Second * 300
)
-func init() {
- // wallet contract derivation
- var keyBytes []byte
- keyBytes, err := hex.DecodeString(strings.TrimPrefix(defaultWalletPrivKey, "0x"))
- if err != nil {
- panic(err)
- }
- defaultWalletAddress = "0x" + hex.EncodeToString(keys.PubKeyToAccount(keys.Raw(keyBytes).Key().PublicKey(), ops.DevnetClassHash, ops.DevnetSalt))
+// OCRv2TestState Main testing state struct
+type OCRv2TestState struct {
+ Account *AccountDetails
+ Clients *Clients
+ PluginNodesK8s []*client.PluginK8sClient
+ Common *Common
+ TestConfig *TestConfig
+ Contracts *Contracts
}
-type Test struct {
- Devnet *devnet.StarknetDevnetClient
- Cc *PluginClient
- Starknet *starknet.Client
- OCR2Client *ocr2.Client
- Sg *gauntlet.StarknetGauntlet
- mockServer *ctfClient.MockserverClient
- L1RPCUrl string
- Common *Common
- AccountAddresses []string
+// AccountDetails for deployment and funding
+type AccountDetails struct {
+ Account string
+ PrivateKey string
+}
+
+// Clients to access internal methods
+type Clients struct {
+ StarknetClient *starknet.Client
+ DevnetClient *starknetdevnet.DevNet
+ KillgraveClient *test_env_ctf.Killgrave
+ OCR2Client *ocr2.Client
+ PluginClient *PluginClient
+ GauntletClient *gauntlet.StarknetGauntlet
+ DockerEnv *StarknetClusterTestEnv
+}
+
+// Contracts to store current deployed contract state
+type Contracts struct {
LinkTokenAddr string
OCRAddr string
AccessControllerAddr string
ProxyAddr string
ObservationSource string
JuelsPerFeeCoinSource string
- T *testing.T
}
+// PluginClient core node configs
type PluginClient struct {
- NKeys []client.NodeKeysBundle
- PluginNodes []*client.Plugin
- bTypeAttr *client.BridgeTypeAttributes
- bootstrapPeers []client.P2PData
+ NKeys []client.NodeKeysBundle
+ PluginNodes []*client.PluginClient
+ bTypeAttr *client.BridgeTypeAttributes
+ bootstrapPeers []client.P2PData
+ AccountAddresses []string
}
-// DeployCluster Deploys and sets up config of the environment and nodes
-func (testState *Test) DeployCluster() {
- lggr := logger.Nop()
- testState.Cc = &PluginClient{}
- testState.ObservationSource = testState.GetDefaultObservationSource()
- testState.JuelsPerFeeCoinSource = testState.GetDefaultJuelsPerFeeCoinSource()
- testState.DeployEnv()
- if testState.Common.Env.WillUseRemoteRunner() {
- return // short circuit here if using a remote runner
+type StarknetClusterTestEnv struct {
+ *test_env.CLClusterTestEnv
+ Starknet *test_env_starknet.Starknet
+ Killgrave *test_env_ctf.Killgrave
+}
+
+type TestConfig struct {
+ T *testing.T
+ L zerolog.Logger
+ TestConfig *testconfig.TestConfig
+ Resty *resty.Client
+ err error
+}
+
+func NewOCRv2State(t *testing.T, namespacePrefix string, testConfig *testconfig.TestConfig) (*OCRv2TestState, error) {
+ c, err := New(testConfig).Default(t, namespacePrefix)
+ if err != nil {
+ return nil, err
}
- testState.SetupClients()
- if testState.Common.Testnet {
- testState.Common.Env.URLs[testState.Common.ServiceKeyL2][1] = testState.Common.L2RPCUrl
+ state := &OCRv2TestState{
+ Account: &AccountDetails{},
+ Clients: &Clients{
+ PluginClient: &PluginClient{},
+ },
+ Common: c,
+ TestConfig: &TestConfig{
+ T: t,
+ L: log.Logger,
+ TestConfig: testConfig,
+ Resty: nil,
+ err: nil,
+ },
+ Contracts: &Contracts{},
}
- var err error
- testState.Cc.NKeys, testState.Cc.PluginNodes, err = testState.Common.CreateKeys(testState.Common.Env)
- require.NoError(testState.T, err, "Creating chains and keys should not fail")
- testState.Starknet, err = starknet.NewClient(testState.Common.ChainId, testState.Common.L2RPCUrl, lggr, &rpcRequestTimeout)
- require.NoError(testState.T, err, "Creating starknet client should not fail")
- testState.OCR2Client, err = ocr2.NewClient(testState.Starknet, lggr)
- require.NoError(testState.T, err, "Creating ocr2 client should not fail")
- if !testState.Common.Testnet {
- err = os.Setenv("PRIVATE_KEY", testState.GetDefaultPrivateKey())
- require.NoError(testState.T, err, "Setting private key should not fail")
- err = os.Setenv("ACCOUNT", testState.GetDefaultWalletAddress())
- require.NoError(testState.T, err, "Setting account address should not fail")
- testState.Devnet.AutoDumpState() // Auto dumping devnet state to avoid losing contracts on crash
+
+ // Setting default job configs
+ state.Contracts.ObservationSource = state.GetDefaultObservationSource()
+ state.Contracts.JuelsPerFeeCoinSource = state.GetDefaultJuelsPerFeeCoinSource()
+
+ if state.TestConfig.T != nil {
+ state.TestConfig.L = logging.GetTestLogger(state.TestConfig.T)
}
+
+ return state, nil
}
-// DeployEnv Deploys the environment
-func (testState *Test) DeployEnv() {
- err := testState.Common.Env.Run()
- require.NoError(testState.T, err)
- if testState.Common.Env.WillUseRemoteRunner() {
- return // short circuit here if using a remote runner
+// DeployCluster Deploys and sets up config of the environment and nodes
+func (m *OCRv2TestState) DeployCluster() {
+ // When running soak we need to use K8S
+ if *m.Common.TestConfig.Common.InsideK8s {
+ m.DeployEnv()
+
+ if m.Common.Env.WillUseRemoteRunner() {
+ return
+ }
+
+ m.Common.RPCDetails.RPCL2External = m.Common.Env.URLs["starknet-dev"][0]
+
+ // Checking whether we are running in a remote runner since the forwarding is not working there and we need the public IP
+ // In that case it is http://127.0.0.1:0 so we do a check and get the public IP
+ if m.Common.RPCDetails.RPCL2External == "http://127.0.0.1:0" {
+ m.Common.RPCDetails.RPCL2External = m.Common.Env.URLs["starknet-dev"][1]
+ }
+
+ // Setting RPC details
+ if *m.Common.TestConfig.Common.Network == "testnet" {
+ m.Common.RPCDetails.RPCL2External = *m.Common.TestConfig.Common.L2RPCUrl
+ m.Common.RPCDetails.RPCL2Internal = *m.Common.TestConfig.Common.L2RPCUrl
+ }
+ m.Common.RPCDetails.MockServerEndpoint = m.Common.Env.URLs["qa_mock_adapter_internal"][0]
+ m.Common.RPCDetails.MockServerURL = "five"
+ } else { // Otherwise use docker
+ env, err := test_env.NewTestEnv()
+ require.NoError(m.TestConfig.T, err)
+ stark := test_env_starknet.NewStarknet([]string{env.DockerNetwork.Name}, *m.Common.TestConfig.Common.DevnetImage)
+ err = stark.StartContainer()
+ require.NoError(m.TestConfig.T, err)
+
+ // Setting RPC details
+ m.Common.RPCDetails.RPCL2External = stark.ExternalHTTPURL
+ m.Common.RPCDetails.RPCL2Internal = stark.InternalHTTPURL
+
+ if *m.Common.TestConfig.Common.Network == "testnet" {
+ m.Common.RPCDetails.RPCL2External = *m.Common.TestConfig.Common.L2RPCUrl
+ m.Common.RPCDetails.RPCL2Internal = *m.Common.TestConfig.Common.L2RPCUrl
+ }
+
+ // Creating docker containers
+ b, err := test_env.NewCLTestEnvBuilder().
+ WithNonEVM().
+ WithTestInstance(m.TestConfig.T).
+ WithTestConfig(m.TestConfig.TestConfig).
+ WithMockAdapter().
+ WithCLNodes(*m.Common.TestConfig.OCR2.NodeCount).
+ WithCLNodeOptions(m.Common.TestEnvDetails.NodeOpts...).
+ WithStandardCleanup().
+ WithTestEnv(env)
+ require.NoError(m.TestConfig.T, err)
+ env, err = b.Build()
+ require.NoError(m.TestConfig.T, err)
+ m.Clients.DockerEnv = &StarknetClusterTestEnv{
+ CLClusterTestEnv: env,
+ Starknet: stark,
+ Killgrave: env.MockAdapter,
+ }
+
+ // Setting up Mock adapter
+ m.Clients.KillgraveClient = env.MockAdapter
+ m.Common.RPCDetails.MockServerEndpoint = m.Clients.KillgraveClient.InternalEndpoint
+ m.Common.RPCDetails.MockServerURL = "mockserver-bridge"
+ err = m.Clients.KillgraveClient.SetAdapterBasedIntValuePath("/mockserver-bridge", []string{http.MethodGet, http.MethodPost}, 10)
+ require.NoError(m.TestConfig.T, err, "Failed to set mock adapter value")
}
- testState.mockServer, err = ctfClient.ConnectMockServer(testState.Common.Env)
- require.NoError(testState.T, err, "Creating mockserver clients shouldn't fail")
-}
-// SetupClients Sets up the starknet client
-func (testState *Test) SetupClients() {
- l := utils.GetTestLogger(testState.T)
- if testState.Common.Testnet {
- l.Debug().Msg(fmt.Sprintf("Overriding L2 RPC: %s", testState.Common.L2RPCUrl))
+ m.TestConfig.Resty = resty.New().SetBaseURL(m.Common.RPCDetails.RPCL2External)
+
+ if *m.Common.TestConfig.Common.InsideK8s {
+ m.PluginNodesK8s, m.TestConfig.err = client.ConnectPluginNodes(m.Common.Env)
+ require.NoError(m.TestConfig.T, m.TestConfig.err)
+ m.Clients.PluginClient.PluginNodes = m.GetPluginNodes()
+ m.Clients.PluginClient.NKeys, m.TestConfig.err = m.Common.CreateNodeKeysBundle(m.Clients.PluginClient.PluginNodes)
+ require.NoError(m.TestConfig.T, m.TestConfig.err)
} else {
- testState.Common.L2RPCUrl = testState.Common.Env.URLs[testState.Common.ServiceKeyL2][0] // For local runs setting local ip
- if testState.Common.Env.Cfg.InsideK8s {
- testState.Common.L2RPCUrl = testState.Common.Env.URLs[testState.Common.ServiceKeyL2][1] // For remote runner setting remote IP
- }
- l.Debug().Msg(fmt.Sprintf("L2 RPC: %s", testState.Common.L2RPCUrl))
- testState.Devnet = testState.Devnet.NewStarknetDevnetClient(testState.Common.L2RPCUrl, dumpPath)
+ m.Clients.PluginClient.PluginNodes = m.Clients.DockerEnv.CLClusterTestEnv.ClCluster.NodeAPIs()
+ m.Clients.PluginClient.NKeys, m.TestConfig.err = m.Common.CreateNodeKeysBundle(m.Clients.DockerEnv.CLClusterTestEnv.ClCluster.NodeAPIs())
+ require.NoError(m.TestConfig.T, m.TestConfig.err)
+ }
+ lggr := logger.Nop()
+ m.Clients.StarknetClient, m.TestConfig.err = starknet.NewClient(m.Common.ChainDetails.ChainID, m.Common.RPCDetails.RPCL2External, m.Common.RPCDetails.RPCL2InternalAPIKey, lggr, &rpcRequestTimeout)
+ require.NoError(m.TestConfig.T, m.TestConfig.err, "Creating starknet client should not fail")
+ m.Clients.OCR2Client, m.TestConfig.err = ocr2.NewClient(m.Clients.StarknetClient, lggr)
+ require.NoError(m.TestConfig.T, m.TestConfig.err, "Creating ocr2 client should not fail")
+
+ // If we are using devnet fetch the default keys
+ if *m.Common.TestConfig.Common.Network == "localnet" {
+ // fetch predeployed account 0 to use as funder
+ m.Clients.DevnetClient = starknetdevnet.NewDevNet(m.Common.RPCDetails.RPCL2External)
+ accounts, err := m.Clients.DevnetClient.Accounts()
+ require.NoError(m.TestConfig.T, err)
+ account := accounts[0]
+ m.Account.Account = account.Address
+ m.Account.PrivateKey = account.PrivateKey
+ } else {
+ m.Account.Account = *m.TestConfig.TestConfig.Common.Account
+ m.Account.PrivateKey = *m.TestConfig.TestConfig.Common.PrivateKey
}
}
+// DeployEnv Deploys the environment
+func (m *OCRv2TestState) DeployEnv() {
+ err := m.Common.Env.Run()
+ require.NoError(m.TestConfig.T, err)
+}
+
// LoadOCR2Config Loads and returns the default starknet gauntlet config
-func (testState *Test) LoadOCR2Config() (*ops.OCR2Config, error) {
+func (m *OCRv2TestState) LoadOCR2Config() (*ops.OCR2Config, error) {
var offChaiNKeys []string
var onChaiNKeys []string
- var peerIds []string
+ var peerIDs []string
var txKeys []string
var cfgKeys []string
- for _, key := range testState.Cc.NKeys {
+ for i, key := range m.Clients.PluginClient.NKeys {
offChaiNKeys = append(offChaiNKeys, key.OCR2Key.Data.Attributes.OffChainPublicKey)
- peerIds = append(peerIds, key.PeerID)
- txKeys = append(txKeys, key.TXKey.Data.ID)
+ peerIDs = append(peerIDs, key.PeerID)
+ txKeys = append(txKeys, m.Clients.PluginClient.AccountAddresses[i])
onChaiNKeys = append(onChaiNKeys, key.OCR2Key.Data.Attributes.OnChainPublicKey)
cfgKeys = append(cfgKeys, key.OCR2Key.Data.Attributes.ConfigPublicKey)
}
@@ -148,85 +255,48 @@ func (testState *Test) LoadOCR2Config() (*ops.OCR2Config, error) {
payload.Signers = onChaiNKeys
payload.Transmitters = txKeys
payload.OffchainConfig.OffchainPublicKeys = offChaiNKeys
- payload.OffchainConfig.PeerIds = peerIds
+ payload.OffchainConfig.PeerIDs = peerIDs
payload.OffchainConfig.ConfigPublicKeys = cfgKeys
return &payload, nil
}
-func (testState *Test) SetUpNodes(mockServerVal int) {
- testState.SetBridgeTypeAttrs(&client.BridgeTypeAttributes{
- Name: "bridge-mockserver",
- URL: testState.GetMockServerURL(),
- })
- err := testState.SetMockServerValue("", mockServerVal)
- require.NoError(testState.T, err, "Setting mock server value should not fail")
- err = testState.Common.CreateJobsForContract(testState.GetPluginClient(), testState.ObservationSource, testState.JuelsPerFeeCoinSource, testState.OCRAddr, testState.AccountAddresses)
- require.NoError(testState.T, err, "Creating jobs should not fail")
-}
-
-// GetStarknetAddress Returns the local StarkNET address
-func (testState *Test) GetStarknetAddress() string {
- return testState.Common.Env.URLs[testState.Common.ServiceKeyL2][0]
-}
-
-// GetStarknetAddressRemote Returns the remote StarkNET address
-func (testState *Test) GetStarknetAddressRemote() string {
- return testState.Common.Env.URLs[testState.Common.ServiceKeyL2][1]
+func (m *OCRv2TestState) SetUpNodes() {
+ err := m.Common.CreateJobsForContract(m.GetPluginClient(), m.Contracts.ObservationSource, m.Contracts.JuelsPerFeeCoinSource, m.Contracts.OCRAddr, m.Clients.PluginClient.AccountAddresses)
+ require.NoError(m.TestConfig.T, err, "Creating jobs should not fail")
}
// GetNodeKeys Returns the node key bundles
-func (testState *Test) GetNodeKeys() []client.NodeKeysBundle {
- return testState.Cc.NKeys
-}
-
-func (testState *Test) GetPluginNodes() []*client.Plugin {
- return testState.Cc.PluginNodes
-}
-
-func (testState *Test) GetDefaultPrivateKey() string {
- return defaultWalletPrivKey
-}
-
-func (testState *Test) GetDefaultWalletAddress() string {
- return defaultWalletAddress
+func (m *OCRv2TestState) GetNodeKeys() []client.NodeKeysBundle {
+ return m.Clients.PluginClient.NKeys
}
-func (testState *Test) GetPluginClient() *PluginClient {
- return testState.Cc
-}
-
-func (testState *Test) GetStarknetDevnetClient() *devnet.StarknetDevnetClient {
- return testState.Devnet
-}
-
-func (testState *Test) SetBridgeTypeAttrs(attr *client.BridgeTypeAttributes) {
- testState.Cc.bTypeAttr = attr
-}
-
-func (testState *Test) GetMockServerURL() string {
- return testState.mockServer.Config.ClusterURL
+func (m *OCRv2TestState) GetPluginNodes() []*client.PluginClient {
+ // retrieve client from K8s client
+ var pluginNodes []*client.PluginClient
+ for i := range m.PluginNodesK8s {
+ pluginNodes = append(pluginNodes, m.PluginNodesK8s[i].PluginClient)
+ }
+ return pluginNodes
}
-func (testState *Test) SetMockServerValue(path string, val int) error {
- return testState.mockServer.SetValuePath(path, val)
+func (m *OCRv2TestState) GetPluginClient() *PluginClient {
+ return m.Clients.PluginClient
}
-// ConfigureL1Messaging Sets the L1 messaging contract location and RPC url on L2
-func (testState *Test) ConfigureL1Messaging() {
- err := testState.Devnet.LoadL1MessagingContract(testState.L1RPCUrl)
- require.NoError(testState.T, err, "Setting up L1 messaging should not fail")
+func (m *OCRv2TestState) SetBridgeTypeAttrs(attr *client.BridgeTypeAttributes) {
+ m.Clients.PluginClient.bTypeAttr = attr
}
-func (testState *Test) GetDefaultObservationSource() string {
+func (m *OCRv2TestState) GetDefaultObservationSource() string {
return `
- val [type = "bridge" name="bridge-mockserver"]
+ val [type = "bridge" name="mockserver-bridge"]
parse [type="jsonparse" path="data,result"]
val -> parse
`
}
-func (testState *Test) GetDefaultJuelsPerFeeCoinSource() string {
+func (m *OCRv2TestState) GetDefaultJuelsPerFeeCoinSource() string {
return `"""
sum [type="sum" values=<[451000]> ]
sum
@@ -234,8 +304,7 @@ func (testState *Test) GetDefaultJuelsPerFeeCoinSource() string {
`
}
-func (testState *Test) ValidateRounds(rounds int, isSoak bool) error {
- l := utils.GetTestLogger(testState.T)
+func (m *OCRv2TestState) ValidateRounds(rounds int, isSoak bool) error {
ctx := context.Background() // context background used because timeout handled by requestTimeout param
// assert new rounds are occurring
details := ocr2.TransmissionDetails{}
@@ -245,26 +314,39 @@ func (testState *Test) ValidateRounds(rounds int, isSoak bool) error {
var positive bool
// validate balance in aggregator
- resLINK, errLINK := testState.Starknet.CallContract(ctx, starknet.CallOps{
- ContractAddress: caigotypes.HexToHash(testState.LinkTokenAddr),
- Selector: "balanceOf",
- Calldata: []string{caigotypes.HexToBN(testState.OCRAddr).String()},
+ linkContractAddress, err := starknetutils.HexToFelt(m.Contracts.LinkTokenAddr)
+ if err != nil {
+ return err
+ }
+ contractAddress, err := starknetutils.HexToFelt(m.Contracts.OCRAddr)
+ if err != nil {
+ return err
+ }
+ resPLI, errPLI := m.Clients.StarknetClient.CallContract(ctx, starknet.CallOps{
+ ContractAddress: linkContractAddress,
+ Selector: starknetutils.GetSelectorFromNameFelt("balance_of"),
+ Calldata: []*felt.Felt{contractAddress},
})
- require.NoError(testState.T, errLINK, "Reader balance from PLI contract should not fail")
- resAgg, errAgg := testState.Starknet.CallContract(ctx, starknet.CallOps{
- ContractAddress: caigotypes.HexToHash(testState.OCRAddr),
- Selector: "link_available_for_payment",
+ require.NoError(m.TestConfig.T, errPLI, "Reader balance from PLI contract should not fail", "err", errPLI)
+ resAgg, errAgg := m.Clients.StarknetClient.CallContract(ctx, starknet.CallOps{
+ ContractAddress: contractAddress,
+ Selector: starknetutils.GetSelectorFromNameFelt("link_available_for_payment"),
})
- require.NoError(testState.T, errAgg, "Reader balance from PLI contract should not fail")
- balLINK, _ := new(big.Int).SetString(resLINK[0], 0)
- balAgg, _ := new(big.Int).SetString(resAgg[0], 0)
- assert.Equal(testState.T, balLINK.Cmp(big.NewInt(0)), 1, "Aggregator should have non-zero balance")
- assert.GreaterOrEqual(testState.T, balLINK.Cmp(balAgg), 0, "Aggregator payment balance should be <= actual PLI balance")
-
- for start := time.Now(); time.Since(start) < testState.Common.TTL; {
- l.Info().Msg(fmt.Sprintf("Elapsed time: %s, Round wait: %s ", time.Since(start), testState.Common.TTL))
- res, err := testState.OCR2Client.LatestTransmissionDetails(ctx, caigotypes.HexToHash(testState.OCRAddr))
- require.NoError(testState.T, err, "Failed to get latest transmission details")
+ require.NoError(m.TestConfig.T, errAgg, "link_available_for_payment should not fail", "err", errAgg)
+ balPLI := resPLI[0].BigInt(big.NewInt(0))
+ balAgg := resAgg[1].BigInt(big.NewInt(0))
+ isNegative := resAgg[0].BigInt(big.NewInt(0))
+ if isNegative.Sign() > 0 {
+ balAgg = new(big.Int).Neg(balAgg)
+ }
+
+ assert.Equal(m.TestConfig.T, balPLI.Cmp(big.NewInt(0)), 1, "Aggregator should have non-zero balance")
+ assert.GreaterOrEqual(m.TestConfig.T, balPLI.Cmp(balAgg), 0, "Aggregator payment balance should be <= actual PLI balance")
+
+ for start := time.Now(); time.Since(start) < m.Common.TestEnvDetails.TestDuration; {
+ m.TestConfig.L.Info().Msg(fmt.Sprintf("Elapsed time: %s, Round wait: %s ", time.Since(start), m.Common.TestEnvDetails.TestDuration))
+ res, err2 := m.Clients.OCR2Client.LatestTransmissionDetails(ctx, contractAddress)
+ require.NoError(m.TestConfig.T, err2, "Failed to get latest transmission details")
// end condition: enough rounds have occurred
if !isSoak && increasing >= rounds && positive {
break
@@ -272,23 +354,18 @@ func (testState *Test) ValidateRounds(rounds int, isSoak bool) error {
// end condition: rounds have been stuck
if stuck && stuckCount > 50 {
- l.Debug().Msg("failing to fetch transmissions means blockchain may have stopped")
+ m.TestConfig.L.Debug().Msg("failing to fetch transmissions means blockchain may have stopped")
break
}
- l.Info().Msg(fmt.Sprintf("Setting adapter value to %d", mockServerValue))
- err = testState.SetMockServerValue("", mockServerValue)
- if err != nil {
- l.Error().Msg(fmt.Sprintf("Setting mock server value error: %+v", err))
- }
// try to fetch rounds
time.Sleep(5 * time.Second)
if err != nil {
- l.Error().Msg(fmt.Sprintf("Transmission Error: %+v", err))
+ m.TestConfig.L.Error().Msg(fmt.Sprintf("Transmission Error: %+v", err))
continue
}
- l.Info().Msg(fmt.Sprintf("Transmission Details: %+v", res))
+ m.TestConfig.L.Info().Msg(fmt.Sprintf("Transmission Details: %+v", res))
// continue if no changes
if res.Epoch == 0 && res.Round == 0 {
@@ -301,21 +378,21 @@ func (testState *Test) ValidateRounds(rounds int, isSoak bool) error {
// if changes from zero values set (should only initially)
if res.Epoch > 0 && details.Epoch == 0 {
if !isSoak {
- assert.Greater(testState.T, res.Epoch, details.Epoch)
- assert.GreaterOrEqual(testState.T, res.Round, details.Round)
- assert.NotEqual(testState.T, ansCmp, 0) // assert changed from 0
- assert.NotEqual(testState.T, res.Digest, details.Digest)
- assert.Equal(testState.T, details.LatestTimestamp.Before(res.LatestTimestamp), true)
+ assert.Greater(m.TestConfig.T, res.Epoch, details.Epoch)
+ assert.GreaterOrEqual(m.TestConfig.T, res.Round, details.Round)
+ assert.NotEqual(m.TestConfig.T, ansCmp, 0) // assert changed from 0
+ assert.NotEqual(m.TestConfig.T, res.Digest, details.Digest)
+ assert.Equal(m.TestConfig.T, details.LatestTimestamp.Before(res.LatestTimestamp), true)
}
details = res
continue
}
// check increasing rounds
if !isSoak {
- assert.Equal(testState.T, res.Digest, details.Digest, "Config digest should not change")
+ assert.Equal(m.TestConfig.T, res.Digest, details.Digest, "Config digest should not change")
} else {
if res.Digest != details.Digest {
- l.Error().Msg(fmt.Sprintf("Config digest should not change, expected %s got %s", details.Digest, res.Digest))
+ m.TestConfig.L.Error().Msg(fmt.Sprintf("Config digest should not change, expected %s got %s", details.Digest, res.Digest))
}
}
if (res.Epoch > details.Epoch || (res.Epoch == details.Epoch && res.Round > details.Round)) && details.LatestTimestamp.Before(res.LatestTimestamp) {
@@ -333,24 +410,31 @@ func (testState *Test) ValidateRounds(rounds int, isSoak bool) error {
}
}
if !isSoak {
- assert.GreaterOrEqual(testState.T, increasing, rounds, "Round + epochs should be increasing")
- assert.Equal(testState.T, positive, true, "Positive value should have been submitted")
- assert.Equal(testState.T, stuck, false, "Round + epochs should not be stuck")
+ assert.GreaterOrEqual(m.TestConfig.T, increasing, rounds, "Round + epochs should be increasing")
+ assert.Equal(m.TestConfig.T, positive, true, "Positive value should have been submitted")
+ assert.Equal(m.TestConfig.T, stuck, false, "Round + epochs should not be stuck")
}
// Test proxy reading
// TODO: would be good to test proxy switching underlying feeds
- roundDataRaw, err := testState.Starknet.CallContract(ctx, starknet.CallOps{
- ContractAddress: caigotypes.HexToHash(testState.ProxyAddr),
- Selector: "latest_round_data",
+
+ proxyAddress, err := starknetutils.HexToFelt(m.Contracts.ProxyAddr)
+ if err != nil {
+ return err
+ }
+ roundDataRaw, err := m.Clients.StarknetClient.CallContract(ctx, starknet.CallOps{
+ ContractAddress: proxyAddress,
+ Selector: starknetutils.GetSelectorFromNameFelt("latest_round_data"),
})
if !isSoak {
- require.NoError(testState.T, err, "Reading round data from proxy should not fail")
- assert.Equal(testState.T, len(roundDataRaw), 5, "Round data from proxy should match expected size")
+ require.NoError(m.TestConfig.T, err, "Reading round data from proxy should not fail")
+ assert.Equal(m.TestConfig.T, len(roundDataRaw), 5, "Round data from proxy should match expected size")
}
- value := starknet.HexToSignedBig(roundDataRaw[1]).Int64()
+ valueBig := roundDataRaw[1].BigInt(big.NewInt(0))
+ require.NoError(m.TestConfig.T, err)
+ value := valueBig.Int64()
if value < 0 {
- assert.Equal(testState.T, value, int64(mockServerValue), "Reading from proxy should return correct value")
+ assert.Equal(m.TestConfig.T, value, int64(5), "Reading from proxy should return correct value")
}
return nil
diff --git a/integration-tests/config/config.go b/integration-tests/config/config.go
new file mode 100644
index 0000000..00dd293
--- /dev/null
+++ b/integration-tests/config/config.go
@@ -0,0 +1,37 @@
+package config
+
+var (
+ starkTokenAddress = "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
+)
+
+type Config struct {
+ ChainName string
+ ChainID string
+ StarkTokenAddress string
+ L2RPCInternal string
+ L2RPCInternalAPIKey string
+ TokenName string
+ FeederURL string
+}
+
+func SepoliaConfig() *Config {
+ return &Config{
+ ChainName: "starknet",
+ ChainID: "SN_SEPOLIA",
+ StarkTokenAddress: starkTokenAddress,
+ // Will be overridden if set in toml
+ L2RPCInternal: "https://starknet-sepolia.public.blastapi.io/rpc/v0_7",
+ FeederURL: "https://alpha-sepolia.starknet.io/feeder_gateway",
+ }
+}
+
+func DevnetConfig() *Config {
+ return &Config{
+ ChainName: "starknet",
+ ChainID: "SN_SEPOLIA",
+ StarkTokenAddress: starkTokenAddress,
+ // Will be overridden if set in toml
+ L2RPCInternal: "http://starknet-dev:5000",
+ TokenName: "FRI",
+ }
+}
diff --git a/integration-tests/docker/testenv/stark.go b/integration-tests/docker/testenv/stark.go
new file mode 100644
index 0000000..f1f0f23
--- /dev/null
+++ b/integration-tests/docker/testenv/stark.go
@@ -0,0 +1,107 @@
+package testenv
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+ tc "github.com/testcontainers/testcontainers-go"
+ tcwait "github.com/testcontainers/testcontainers-go/wait"
+
+ "github.com/goplugin/plugin-testing-framework/docker/test_env"
+ "github.com/goplugin/plugin-testing-framework/logging"
+ "github.com/goplugin/plugin-testing-framework/utils/testcontext"
+)
+
+const (
+ StarkHTTPPort = "5050"
+)
+
+type Starknet struct {
+ test_env.EnvComponent
+ ExternalHTTPURL string
+ InternalHTTPURL string
+ t *testing.T
+ l zerolog.Logger
+ Image string
+}
+
+func NewStarknet(networks []string, image string, opts ...test_env.EnvComponentOption) *Starknet {
+ ms := &Starknet{
+ Image: image,
+ EnvComponent: test_env.EnvComponent{
+ ContainerName: "starknet",
+ Networks: networks,
+ },
+
+ l: log.Logger,
+ }
+ for _, opt := range opts {
+ opt(&ms.EnvComponent)
+ }
+ return ms
+}
+
+func (s *Starknet) WithTestLogger(t *testing.T) *Starknet {
+ s.l = logging.GetTestLogger(t)
+ s.t = t
+ return s
+}
+
+func (s *Starknet) StartContainer() error {
+ l := tc.Logger
+ if s.t != nil {
+ l = logging.CustomT{
+ T: s.t,
+ L: s.l,
+ }
+ }
+ cReq, err := s.getContainerRequest()
+ if err != nil {
+ return err
+ }
+ c, err := tc.GenericContainer(testcontext.Get(s.t), tc.GenericContainerRequest{
+ ContainerRequest: *cReq,
+ Reuse: true,
+ Started: true,
+ Logger: l,
+ })
+ if err != nil {
+ return fmt.Errorf("cannot start Starknet container: %w", err)
+ }
+ s.Container = c
+ host, err := test_env.GetHost(testcontext.Get(s.t), c)
+ if err != nil {
+ return err
+ }
+ httpPort, err := c.MappedPort(testcontext.Get(s.t), test_env.NatPort(StarkHTTPPort))
+ if err != nil {
+ return err
+ }
+
+ s.ExternalHTTPURL = fmt.Sprintf("http://%s:%s", host, httpPort.Port())
+ s.InternalHTTPURL = fmt.Sprintf("http://%s:%s", s.ContainerName, StarkHTTPPort)
+
+ s.l.Info().
+ Any("ExternalHTTPURL", s.ExternalHTTPURL).
+ Any("InternalHTTPURL", s.InternalHTTPURL).
+ Str("containerName", s.ContainerName).
+ Msgf("Started Starknet container")
+
+ return nil
+}
+
+func (s *Starknet) getContainerRequest() (*tc.ContainerRequest, error) {
+ return &tc.ContainerRequest{
+ Name: s.ContainerName,
+ Image: s.Image,
+ ExposedPorts: []string{test_env.NatPortFormat(StarkHTTPPort)},
+ Networks: s.Networks,
+ WaitingFor: tcwait.ForLog("Starknet Devnet listening").
+ WithStartupTimeout(30 * time.Second).
+ WithPollInterval(100 * time.Millisecond),
+ Entrypoint: []string{"sh", "-c", "tini -- starknet-devnet --host 0.0.0.0 --port 5050 --seed 0 --account-class cairo1 --gas-price 1 --data-gas-price 1"},
+ }, nil
+}
diff --git a/integration-tests/go.mod b/integration-tests/go.mod
index f62a0c8..d655fe8 100644
--- a/integration-tests/go.mod
+++ b/integration-tests/go.mod
@@ -1,381 +1,516 @@
module github.com/goplugin/plugin-starknet/integration-tests
-go 1.20
+go 1.22.5
require (
- github.com/dontpanicdao/caigo v0.4.0
- github.com/rs/zerolog v1.29.1
- github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
- github.com/goplugin/plugin-env v0.3.29
- github.com/goplugin/plugin-starknet/ops v0.0.0-20230329050701-40e3b18bb026
- github.com/goplugin/plugin-starknet/relayer v0.0.0-20230424184429-bfdf6bddb239
- github.com/goplugin/plugin-testing-framework v1.11.5
- github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20230420131147-ce3c53a39d07
- github.com/goplugin/pluginv3.0/v2 v2.1.0-beta0.0.20230427051455-edb338fd2536
+ github.com/NethermindEth/juno v0.3.1
+ github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb
+ github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df
+ github.com/go-resty/resty/v2 v2.11.0
+ github.com/google/uuid v1.6.0
+ github.com/lib/pq v1.10.9
+ github.com/pelletier/go-toml/v2 v2.2.2
+ github.com/rs/zerolog v1.32.0
+ github.com/goplugin/plugin-common v0.0.1-beta //plugin update changes
+ github.com/goplugin/plugin-starknet/ops v0.0.2 //plugin update changes
+ github.com/goplugin/plugin-starknet/relayer v0.0.3-beta //plugin update changes
+ github.com/goplugin/plugin-testing-framework v0.0.1 //plugin update changes
+ github.com/goplugin/pluginv3.0/integration-tests v2.2.0 //plugin update changes
+ github.com/goplugin/pluginv3.0/v2 v2.2.0 //plugin update changes
+ github.com/goplugin/seth v1.0.12
+ //github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b
+ //github.com/goplugin/plugin-starknet/ops v0.0.0-20231205180940-ea2e3e916725
+ //github.com/goplugin/plugin-starknet/relayer v0.0.1-beta-test.0.20240911160128-83c49f033146
+ //github.com/goplugin/plugin-testing-framework v1.33.0
+ //github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20240708135824-bf9122a8cee6
+ //github.com/goplugin/pluginv3.0/v2 v2.14.0-mercury-20240807.0.20240911170808-18cc10abf094
+ //github.com/goplugin/seth v1.0.12
+ github.com/stretchr/testify v1.9.0
+ github.com/testcontainers/testcontainers-go v0.28.0
+ go.uber.org/zap v1.27.0
+ golang.org/x/text v0.18.0
+ gopkg.in/guregu/null.v4 v4.0.0
)
require (
- contrib.go.opencensus.io/exporter/stackdriver v0.13.4 // indirect
- filippo.io/edwards25519 v1.0.0-rc.1 // indirect
+ contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect
+ cosmossdk.io/api v0.3.1 // indirect
+ cosmossdk.io/core v0.5.1 // indirect
+ cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
+ cosmossdk.io/errors v1.0.1 // indirect
+ cosmossdk.io/math v1.3.0 // indirect
+ dario.cat/mergo v1.0.0 // indirect
+ filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
- github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
- github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect
+ github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect
+ github.com/CosmWasm/wasmd v0.40.1 // indirect
+ github.com/CosmWasm/wasmvm v1.2.4 // indirect
github.com/DataDog/zstd v1.5.2 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
- github.com/Masterminds/semver/v3 v3.2.0 // indirect
- github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac // indirect
- github.com/VictoriaMetrics/fastcache v1.10.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/Microsoft/hcsshim v0.11.4 // indirect
+ github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
+ github.com/XSAM/otelsql v0.27.0 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
- github.com/armon/go-metrics v0.4.0 // indirect
+ github.com/armon/go-metrics v0.4.1 // indirect
+ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect
+ github.com/avast/retry-go/v4 v4.6.0 // indirect
+ github.com/aws/aws-sdk-go v1.45.25 // indirect
github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect
github.com/aws/jsii-runtime-go v1.75.0 // indirect
- github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect
- github.com/benbjohnson/clock v1.3.0 // indirect
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
+ github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/bgentry/speakeasy v0.1.0 // indirect
+ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
+ github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
- github.com/btcsuite/btcd v0.23.4 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
+ github.com/buger/jsonparser v1.1.1 // indirect
+ github.com/bytedance/sonic v1.10.1 // indirect
+ github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect
+ github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect
+ github.com/cenkalti/backoff v2.2.1+incompatible // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
- github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 // indirect
- github.com/cockroachdb/errors v1.9.1 // indirect
+ github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f // indirect
+ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
+ github.com/chenzhuoyu/iasm v0.9.0 // indirect
+ github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
- github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
- github.com/cockroachdb/redact v1.1.3 // indirect
- github.com/confio/ics23/go v0.7.0 // indirect
- github.com/cosmos/btcutil v1.0.4 // indirect
- github.com/cosmos/cosmos-sdk v0.45.11 // indirect
+ github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect
+ github.com/cockroachdb/redact v1.1.5 // indirect
+ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
+ github.com/cometbft/cometbft v0.37.5 // indirect
+ github.com/cometbft/cometbft-db v0.8.0 // indirect
+ github.com/confio/ics23/go v0.9.0 // indirect
+ github.com/consensys/bavard v0.1.13 // indirect
+ github.com/consensys/gnark-crypto v0.12.1 // indirect
+ github.com/containerd/containerd v1.7.12 // indirect
+ github.com/containerd/continuity v0.4.3 // indirect
+ github.com/containerd/log v0.1.0 // indirect
+ github.com/coreos/go-semver v0.3.1 // indirect
+ github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+ github.com/cosmos/btcutil v1.0.5 // indirect
+ github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
+ github.com/cosmos/cosmos-sdk v0.47.11 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
- github.com/cosmos/gorocksdb v1.2.0 // indirect
- github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
- github.com/cosmos/ledger-go v0.9.2 // indirect
+ github.com/cosmos/gogoproto v1.4.11 // indirect
+ github.com/cosmos/iavl v0.20.1 // indirect
+ github.com/cosmos/ibc-go/v7 v7.3.1 // indirect
+ github.com/cosmos/ics23/go v0.10.0 // indirect
+ github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect
+ github.com/cpuguy83/dockercfg v0.3.1 // indirect
+ github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect
+ github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
- github.com/deckarep/golang-set/v2 v2.1.0 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/deckarep/golang-set/v2 v2.6.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
+ github.com/dennwc/varint v1.0.0 // indirect
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
- github.com/dgraph-io/ristretto v0.1.0 // indirect
+ github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
+ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+ github.com/distribution/reference v0.5.0 // indirect
+ github.com/docker/distribution v2.8.2+incompatible // indirect
+ github.com/docker/docker v25.0.2+incompatible // indirect
+ github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
- github.com/dustin/go-humanize v1.0.0 // indirect
- github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
+ github.com/dominikbraun/graph v0.23.0 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/dvsekhvalnov/jose2go v1.7.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
- github.com/emicklei/go-restful/v3 v3.9.0 // indirect
- github.com/ethereum/go-ethereum v1.11.5 // indirect
+ github.com/emicklei/go-restful/v3 v3.10.2 // indirect
+ github.com/esote/minmaxheap v1.0.0 // indirect
+ github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
+ github.com/ethereum/go-ethereum v1.13.8 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
+ github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
github.com/fatih/camelcase v1.0.0 // indirect
- github.com/fatih/color v1.15.0 // indirect
- github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect
- github.com/fsnotify/fsnotify v1.6.0 // indirect
- github.com/fvbommel/sortorder v1.0.2 // indirect
- github.com/fxamacker/cbor/v2 v2.4.0 // indirect
- github.com/gagliardetto/binary v0.7.1 // indirect
- github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // indirect
+ github.com/fatih/color v1.16.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/fvbommel/sortorder v1.1.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.7.0 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+ github.com/gagliardetto/binary v0.7.7 // indirect
+ github.com/gagliardetto/solana-go v1.8.4 // indirect
github.com/gagliardetto/treeout v0.1.4 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
- github.com/getsentry/sentry-go v0.19.0 // indirect
+ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
+ github.com/getsentry/sentry-go v0.23.0 // indirect
github.com/gin-contrib/sessions v0.0.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/gin-gonic/gin v1.8.2 // indirect
+ github.com/gin-gonic/gin v1.9.1 // indirect
+ github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/go-errors/errors v1.4.2 // indirect
+ github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
- github.com/go-logfmt/logfmt v0.5.1 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
+ github.com/go-ldap/ldap/v3 v3.4.6 // indirect
+ github.com/go-logfmt/logfmt v0.6.0 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/go-openapi/jsonpointer v0.19.6 // indirect
+ github.com/go-openapi/analysis v0.21.4 // indirect
+ github.com/go-openapi/errors v0.20.4 // indirect
+ github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
- github.com/go-playground/locales v0.14.0 // indirect
- github.com/go-playground/universal-translator v0.18.0 // indirect
- github.com/go-playground/validator/v10 v10.11.1 // indirect
- github.com/go-resty/resty/v2 v2.7.0 // indirect
- github.com/go-stack/stack v1.8.1 // indirect
- github.com/goccy/go-json v0.9.11 // indirect
+ github.com/go-openapi/loads v0.21.2 // indirect
+ github.com/go-openapi/spec v0.20.9 // indirect
+ github.com/go-openapi/strfmt v0.21.7 // indirect
+ github.com/go-openapi/swag v0.22.4 // indirect
+ github.com/go-openapi/validate v0.22.1 // indirect
+ github.com/go-playground/locales v0.14.1 // indirect
+ github.com/go-playground/universal-translator v0.18.1 // indirect
+ github.com/go-playground/validator/v10 v10.15.5 // indirect
+ github.com/go-redis/redis/v8 v8.11.5 // indirect
+ github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
+ github.com/go-webauthn/webauthn v0.9.4 // indirect
+ github.com/go-webauthn/x v0.1.5 // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
+ github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
- github.com/golang/glog v1.0.0 // indirect
+ github.com/gogo/status v1.1.1 // indirect
+ github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
+ github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/golang/protobuf v1.5.3 // indirect
- github.com/golang/snappy v0.0.4 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/btree v1.1.2 // indirect
- github.com/google/gnostic v0.6.9 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/gnostic-models v0.6.8 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/google/go-github/v41 v41.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
+ github.com/google/go-tpm v0.9.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
- github.com/google/gopacket v1.1.19 // indirect
- github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
+ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/context v1.1.1 // indirect
- github.com/gorilla/securecookie v1.1.1 // indirect
- github.com/gorilla/sessions v1.2.1 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/gorilla/mux v1.8.0 // indirect
+ github.com/gorilla/securecookie v1.1.2 // indirect
+ github.com/gorilla/sessions v1.2.2 // indirect
+ github.com/gorilla/websocket v1.5.1 // indirect
+ github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f // indirect
+ github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 // indirect
+ github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240326122733-6f96a993222b // indirect
+ github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect
+ github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 // indirect
+ github.com/grafana/pyroscope-go v1.1.1 // indirect
+ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
+ github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
+ github.com/hashicorp/consul/api v1.25.1 // indirect
+ github.com/hashicorp/consul/sdk v0.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+ github.com/hashicorp/go-envparse v0.1.0 // indirect
+ github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
+ github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
+ github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99 // indirect
+ github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
+ github.com/hashicorp/go-rootcerts v1.0.2 // indirect
+ github.com/hashicorp/go-sockaddr v1.0.2 // indirect
+ github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
- github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
+ github.com/hashicorp/memberlist v0.5.0 // indirect
+ github.com/hashicorp/serf v0.10.1 // indirect
+ github.com/hashicorp/yamux v0.1.1 // indirect
+ github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
- github.com/holiman/uint256 v1.2.0 // indirect
- github.com/huin/goupnp v1.0.3 // indirect
- github.com/imdario/mergo v0.3.13 // indirect
- github.com/inconshreveable/mousetrap v1.0.1 // indirect
- github.com/ipfs/go-cid v0.0.7 // indirect
- github.com/ipfs/go-datastore v0.4.5 // indirect
- github.com/ipfs/go-ipfs-util v0.0.2 // indirect
- github.com/ipfs/go-ipns v0.0.2 // indirect
- github.com/ipfs/go-log v1.0.4 // indirect
- github.com/ipfs/go-log/v2 v2.1.1 // indirect
+ github.com/holiman/uint256 v1.2.4 // indirect
+ github.com/huandu/skiplist v1.2.0 // indirect
+ github.com/huandu/xstrings v1.4.0 // indirect
+ github.com/huin/goupnp v1.3.0 // indirect
+ github.com/imdario/mergo v0.3.16 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/invopop/jsonschema v0.12.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
- github.com/jackc/pgconn v1.14.0 // indirect
+ github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
- github.com/jackc/pgproto3/v2 v2.3.2 // indirect
+ github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
- github.com/jackc/pgx/v4 v4.18.1 // indirect
+ github.com/jackc/pgx/v4 v4.18.2 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
- github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
- github.com/jbenet/goprocess v0.1.4 // indirect
+ github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
- github.com/jmoiron/sqlx v1.3.5 // indirect
+ github.com/jmoiron/sqlx v1.4.0 // indirect
+ github.com/joho/godotenv v1.5.1 // indirect
+ github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
- github.com/klauspost/compress v1.16.3 // indirect
- github.com/koron/go-ssdp v0.0.2 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
+ github.com/kylelemons/godebug v1.1.0 // indirect
github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect
- github.com/leodido/go-urn v1.2.1 // indirect
- github.com/lib/pq v1.10.8
- github.com/libp2p/go-addr-util v0.0.2 // indirect
+ github.com/leodido/go-urn v1.2.4 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
- github.com/libp2p/go-cidranger v1.1.0 // indirect
- github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect
- github.com/libp2p/go-eventbus v0.2.1 // indirect
- github.com/libp2p/go-flow-metrics v0.0.3 // indirect
- github.com/libp2p/go-libp2p v0.13.0 // indirect
- github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect
- github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect
- github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect
- github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect
- github.com/libp2p/go-libp2p-core v0.8.5 // indirect
- github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect
- github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect
- github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect
- github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect
- github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect
- github.com/libp2p/go-libp2p-nat v0.0.6 // indirect
- github.com/libp2p/go-libp2p-noise v0.1.2 // indirect
- github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect
- github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect
- github.com/libp2p/go-libp2p-record v0.1.3 // indirect
- github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect
- github.com/libp2p/go-libp2p-tls v0.1.3 // indirect
- github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect
- github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect
- github.com/libp2p/go-mplex v0.3.0 // indirect
- github.com/libp2p/go-msgio v0.0.6 // indirect
- github.com/libp2p/go-nat v0.0.5 // indirect
- github.com/libp2p/go-netroute v0.1.4 // indirect
- github.com/libp2p/go-openssl v0.0.7 // indirect
- github.com/libp2p/go-reuseport v0.0.2 // indirect
- github.com/libp2p/go-reuseport-transport v0.0.4 // indirect
- github.com/libp2p/go-sockaddr v0.1.0 // indirect
- github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect
- github.com/libp2p/go-tcp-transport v0.2.1 // indirect
- github.com/libp2p/go-ws-transport v0.4.0 // indirect
- github.com/libp2p/go-yamux/v2 v2.0.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/linxGnu/grocksdb v1.7.16 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
- github.com/magiconair/properties v1.8.6 // indirect
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
- github.com/mattn/go-runewidth v0.0.13 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/miekg/dns v1.1.56 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
- github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
- github.com/minio/sha256-simd v0.1.1 // indirect
+ github.com/mitchellh/copystructure v1.2.0 // indirect
+ github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/mitchellh/reflectwalk v1.0.2 // indirect
+ github.com/mmcloughlin/addchain v0.4.0 // indirect
+ github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
- github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
+ github.com/moby/sys/sequential v0.5.0 // indirect
+ github.com/moby/sys/user v0.1.0 // indirect
+ github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
+ github.com/montanaflynn/stats v0.7.1 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
- github.com/multiformats/go-base32 v0.0.3 // indirect
- github.com/multiformats/go-base36 v0.1.0 // indirect
- github.com/multiformats/go-multiaddr v0.3.3 // indirect
- github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect
- github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
- github.com/multiformats/go-multiaddr-net v0.2.0 // indirect
- github.com/multiformats/go-multibase v0.0.3 // indirect
- github.com/multiformats/go-multihash v0.0.14 // indirect
- github.com/multiformats/go-multistream v0.2.2 // indirect
- github.com/multiformats/go-varint v0.0.6 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
+ github.com/oklog/run v1.1.0 // indirect
+ github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
+ github.com/opencontainers/runc v1.1.10 // indirect
+ github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect
+ github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
+ github.com/otiai10/copy v1.14.0 // indirect
+ github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
+ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
- github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
- github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
+ github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
+ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
- github.com/prometheus/client_golang v1.15.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.9.0 // indirect
- github.com/pyroscope-io/client v0.7.0 // indirect
- github.com/pyroscope-io/godeltaprof v0.1.0 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/prometheus/alertmanager v0.26.0 // indirect
+ github.com/prometheus/client_golang v1.20.0 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.59.1 // indirect
+ github.com/prometheus/common/sigv4 v0.1.0 // indirect
+ github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/prometheus/prometheus v0.48.1 // indirect
+ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
- github.com/rogpeppe/go-internal v1.10.0 // indirect
- github.com/russross/blackfriday v1.6.0 // indirect
+ github.com/rogpeppe/go-internal v1.12.0 // indirect
+ github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/sagikazarmark/locafero v0.4.0 // indirect
+ github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/scylladb/go-reflectx v1.0.1 // indirect
+ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
+ github.com/segmentio/ksuid v1.0.4 // indirect
+ github.com/sercand/kuberesolver/v5 v5.1.1 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
- github.com/shirou/gopsutil/v3 v3.22.12 // indirect
- github.com/shopspring/decimal v1.3.1 // indirect
- github.com/sirupsen/logrus v1.9.0 // indirect
+ github.com/shirou/gopsutil/v3 v3.24.3 // indirect
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/slack-go/slack v0.12.2 // indirect
- github.com/goplugin/plugin-relay v0.1.7-0.20230424181359-6cb4dc745ec7
- github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc // indirect
- github.com/smartcontractkit/ocr2keepers v0.6.14 // indirect
- github.com/smartcontractkit/ocr2vrf v0.0.0-20230425184732-a793ac75f0a3 // indirect
- github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect
- github.com/goplugin/wsrpc v0.6.2-0.20230317160629-382a1ac921d8 // indirect
- github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
- github.com/spaolacci/murmur3 v1.1.0 // indirect
- github.com/spf13/afero v1.9.2 // indirect
- github.com/spf13/cast v1.5.0 // indirect
- github.com/spf13/cobra v1.6.0 // indirect
- github.com/spf13/jwalterweatherman v1.1.0 // indirect
+ github.com/goplugin/chain-selectors v0.1.1 //plugin update changes
+ github.com/goplugin/plugin-automation v0.0.1-beta //plugin update changes
+ github.com/goplugin/plugin-ccip v0.0.1 //plugin update changes
+ github.com/goplugin/plugin-cosmos v0.0.2-beta //plugin update changes
+ github.com/goplugin/plugin-data-streams v0.1.1-beta //plugin update changes
+ github.com/goplugin/plugin-feeds v0.1.1-beta //plugin update changes
+ github.com/goplugin/plugin-solana v0.0.1-beta //plugin update changes
+ github.com/goplugin/plugin-testing-framework/grafana v0.0.1 //plugin update changes
+ github.com/goplugin/grpc-proxy v0.1.1 //plugin update changes
+ github.com/goplugin/plugin-libocr v0.1.1-beta //plugin update changes
+ github.com/goplugin/tdh2/go/ocr2/decryptionplugin v0.2.1 //plugin update changes
+ github.com/goplugin/tdh2/go/tdh2 v0.2.1 //plugin update changes
+ //github.com/goplugin/chain-selectors v1.0.23 // indirect
+ //github.com/goplugin/plugin-automation v1.0.4 // indirect
+ //github.com/goplugin/plugin-ccip v0.0.0-20240911145028-d346e3ace978 // indirect
+ //github.com/goplugin/plugin-cosmos v0.4.1-0.20240911160024-c1da28250122 // indirect
+ //github.com/goplugin/plugin-data-streams v0.0.0-20240906125718-9f0a98d32fbc // indirect
+ //github.com/goplugin/plugin-feeds v0.0.0-20240910155501-42f20443189f // indirect
+ //github.com/goplugin/plugin-solana v1.1.1-0.20240911160840-cde14abca28e // indirect
+ //github.com/goplugin/plugin-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 // indirect
+ //github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect
+ //github.com/goplugin/plugin-libocr v0.0.0-20240717100443-f6226e09bee7 // indirect
+ //github.com/goplugin/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect
+ //github.com/goplugin/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect
+ //github.com/goplugin/wasp v0.1.2 //plugin updaet changes
+ //github.com/goplugin/wasp v0.4.7 // indirect
+ github.com/goplugin/wsrpc v0.1.1 //plugin updaet changes
+ //github.com/goplugin/wsrpc v0.8.2 // indirect
+ github.com/soheilhy/cmux v0.1.5 // indirect
+ github.com/sony/gobreaker v0.5.0 // indirect
+ github.com/sourcegraph/conc v0.3.0 // indirect
+ github.com/spf13/afero v1.11.0 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
+ github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
- github.com/spf13/viper v1.14.0 // indirect
+ github.com/spf13/viper v1.18.2 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/stretchr/testify v1.8.2
- github.com/subosito/gotenv v1.4.1 // indirect
- github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
- github.com/tendermint/btcd v0.1.1 // indirect
- github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect
+ github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/subosito/gotenv v1.6.0 // indirect
+ github.com/supranational/blst v0.3.11 // indirect
+ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
- github.com/tendermint/tendermint v0.34.23 // indirect
- github.com/tendermint/tm-db v0.6.7 // indirect
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 // indirect
+ github.com/test-go/testify v1.1.4 // indirect
github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a // indirect
- github.com/tidwall/gjson v1.14.4 // indirect
+ github.com/tidwall/btree v1.6.0 // indirect
+ github.com/tidwall/gjson v1.17.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
- github.com/tklauser/go-sysconf v0.3.11 // indirect
- github.com/tklauser/numcpus v0.6.0 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
+ github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect
+ github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
+ github.com/ugorji/go/codec v1.2.12 // indirect
github.com/umbracle/ethgo v0.1.3 // indirect
github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect
github.com/valyala/fastjson v1.4.1 // indirect
- github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
- github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
+ github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/x448/float16 v0.8.4 // indirect
- github.com/xlab/treeprint v1.1.0 // indirect
- github.com/yuin/goldmark v1.4.13 // indirect
- github.com/yusufpapurcu/wmi v1.2.2 // indirect
- github.com/zondax/hid v0.9.0 // indirect
+ github.com/xlab/treeprint v1.2.0 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ github.com/zondax/hid v0.9.2 // indirect
+ github.com/zondax/ledger-go v0.14.3 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
- go.dedis.ch/kyber/v3 v3.0.14 // indirect
- go.etcd.io/bbolt v1.3.6 // indirect
+ go.dedis.ch/kyber/v3 v3.1.0 // indirect
+ go.etcd.io/bbolt v1.3.7 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.10 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.10 // indirect
+ go.mongodb.org/mongo-driver v1.15.0 // indirect
go.opencensus.io v0.24.0 // indirect
- go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect
- go.uber.org/atomic v1.10.0 // indirect
- go.uber.org/multierr v1.10.0 // indirect
- go.uber.org/zap v1.24.0
- golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
- golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
- golang.org/x/mod v0.9.0 // indirect
- golang.org/x/net v0.9.0 // indirect
- golang.org/x/oauth2 v0.6.0 // indirect
- golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.7.0 // indirect
- golang.org/x/term v0.7.0 // indirect
- golang.org/x/text v0.9.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.7.0 // indirect
- gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
- gonum.org/v1/gonum v0.12.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 // indirect
- google.golang.org/grpc v1.53.0 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
- gopkg.in/guregu/null.v4 v4.0.0
+ go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect
+ go.opentelemetry.io/collector/semconv v0.87.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
+ go.opentelemetry.io/otel v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
+ go.opentelemetry.io/otel/log v0.4.0 // indirect
+ go.opentelemetry.io/otel/metric v1.28.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.28.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect
+ go.opentelemetry.io/otel/trace v1.28.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.3.1 // indirect
+ go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
+ go.uber.org/atomic v1.11.0 // indirect
+ go.uber.org/goleak v1.3.0 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ go.uber.org/ratelimit v0.3.0 // indirect
+ go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect
+ golang.org/x/arch v0.8.0 // indirect
+ golang.org/x/crypto v0.27.0 // indirect
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.29.0 // indirect
+ golang.org/x/oauth2 v0.22.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
+ golang.org/x/term v0.24.0 // indirect
+ golang.org/x/time v0.6.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
+ gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+ gonum.org/v1/gonum v0.15.0 // indirect
+ google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
+ google.golang.org/grpc v1.65.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
- gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
- gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.25.4 // indirect
- k8s.io/apiextensions-apiserver v0.25.3 // indirect
- k8s.io/apimachinery v0.25.4 // indirect
- k8s.io/cli-runtime v0.25.4 // indirect
- k8s.io/client-go v0.25.4 // indirect
- k8s.io/component-base v0.25.4 // indirect
- k8s.io/klog/v2 v2.80.1 // indirect
- k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
- k8s.io/kubectl v0.25.4 // indirect
- k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
- sigs.k8s.io/controller-runtime v0.13.0 // indirect
- sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
- sigs.k8s.io/kustomize/api v0.12.1 // indirect
- sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
- sigs.k8s.io/yaml v1.3.0 // indirect
+ k8s.io/api v0.28.2 // indirect
+ k8s.io/apiextensions-apiserver v0.28.2 // indirect
+ k8s.io/apimachinery v0.28.2 // indirect
+ k8s.io/cli-runtime v0.28.2 // indirect
+ k8s.io/client-go v0.28.2 // indirect
+ k8s.io/component-base v0.28.2 // indirect
+ k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
+ k8s.io/kubectl v0.28.2 // indirect
+ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+ nhooyr.io/websocket v1.8.10 // indirect
+ pgregory.net/rapid v1.1.0 // indirect
+ rsc.io/tmplfunc v0.0.3 // indirect
+ sigs.k8s.io/controller-runtime v0.16.2 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
+ sigs.k8s.io/yaml v1.4.0 // indirect
)
replace (
- // Fix go mod tidy issue for ambiguous imports from go-ethereum
- // See https://github.com/ugorji/go/issues/279
- github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1
-
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
- github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.14.0
-
- github.com/prometheus/common => github.com/prometheus/common v0.10.0
-
- github.com/satori/go.uuid => github.com/satori/go.uuid v1.2.0
+ // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69
+ github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.1.1 //plugin update changes
+ //github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.0.0-20230731113816-f1be6620749f
// Make sure we're working with the latest ops
github.com/goplugin/plugin-starknet/ops => ../ops
github.com/goplugin/plugin-starknet/relayer => ../relayer
-
- // K8s imports are weird
- k8s.io/api => k8s.io/api v0.25.4
- k8s.io/client-go => k8s.io/client-go v0.25.4
)
diff --git a/integration-tests/go.sum b/integration-tests/go.sum
index b19c47d..c0aae3b 100644
--- a/integration-tests/go.sum
+++ b/integration-tests/go.sum
@@ -4,7 +4,6 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@@ -15,18 +14,26 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
-cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
-cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
+cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
+cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
+cloud.google.com/go/auth v0.7.1 h1:Iv1bbpzJ2OIg16m94XI9/tlzZZl3cdeR3nGVGj78N7s=
+cloud.google.com/go/auth v0.7.1/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
+cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
+cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/compute v1.27.2 h1:5cE5hdrwJV/92ravlwIFRGnyH9CpLGhh4N0ZDVTU+BA=
+cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
+cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw=
+cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -36,389 +43,600 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
+cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
+cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.4 h1:ksUxwH3OD5sxkjzEqGxNTl+Xjsmu3BnC/300MhSVTSc=
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.5 h1:TNaexHK16gPUoc7uzELKOU7JULqccn1NDuqUxmxSqfo=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
+cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE=
+cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw=
+cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI=
+cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE=
+cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc=
+cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU=
+cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
+cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U=
+cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI=
+cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM=
+cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE=
+cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k=
+cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw=
+cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw=
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o=
github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI=
github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE=
-github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
-github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0=
+github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
+github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg=
-github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
-github.com/CosmWasm/wasmd v0.30.0 h1:oUVz3TgO/+24JZQdoTOlOv+IK7N9hEa/s3M4eR9i4FQ=
-github.com/CosmWasm/wasmvm v1.1.1 h1:0xtdrmmsP9fibe+x42WcMkp5aQ738BICgcH3FNVLzm4=
+github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM=
+github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4=
+github.com/CosmWasm/wasmd v0.40.1 h1:LxbO78t/6S8TkeQlUrJ0m5O87HtAwLx4RGHq3rdrOEU=
+github.com/CosmWasm/wasmd v0.40.1/go.mod h1:6EOwnv7MpuFaEqxcUOdFV9i4yvrdOciaY6VQ1o7A3yg=
+github.com/CosmWasm/wasmvm v1.2.4 h1:6OfeZuEcEH/9iqwrg2pkeVtDCkMoj9U6PpKtcrCyVrQ=
+github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
-github.com/Depado/ginprom v1.7.4 h1:4cV9RYKIkT28tZhBDam0p8me2RLypxS0in5Jw4zbcgg=
+github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo=
+github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
-github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac h1:TQ2m26VW06Df1P82Ed/jZhBtf13pReWyl2XQ8hy+J08=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac/go.mod h1:FTk2+xybtQe5X+oNFx+a0n5EeZMD9Nc+LCH4fxFwrEE=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+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/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
+github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
+github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA=
+github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q=
+github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb h1:Mv8SscePPyw2ju4igIJAjFgcq5zCQfjgbz53DwYu5mc=
+github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb/go.mod h1:gQkhWpAs9/QR6reZU2xoi1UIYlMS64FLTlh9CrgHH/Y=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
-github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY=
-github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8=
+github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
+github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
+github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
-github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/Workiva/go-datastructures v1.1.0 h1:hu20UpgZneBhQ3ZvwiOGlqJSKIosin2Rd5wAKUHEO/k=
+github.com/Workiva/go-datastructures v1.1.0/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A=
+github.com/XSAM/otelsql v0.27.0 h1:i9xtxtdcqXV768a5C6SoT/RkG+ue3JTOgkYInzlTOqs=
+github.com/XSAM/otelsql v0.27.0/go.mod h1:0mFB3TvLa7NCuhm/2nU7/b2wEtsczkj8Rey8ygO7V+A=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
+github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
+github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
+github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo=
+github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
-github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
+github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q=
-github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
+github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
+github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/ava-labs/coreth v0.11.0-rc.4 h1:oYZMWZcXYa4dH2hQBIAH/DD0rL2cB3btPGdabpCH5Ug=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4=
+github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g=
github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI=
github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4=
github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I=
-github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=
-github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
+github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0=
+github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
-github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
-github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
+github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
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/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
+github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s=
+github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+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/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
-github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
-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/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
-github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
-github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
-github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
-github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
-github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
-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/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ=
+github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
+github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
+github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA=
+github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM=
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
+github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc=
+github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
+github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY=
+github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
+github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g=
+github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE=
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0=
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5/go.mod h1:R/pdNYDYFQk+tuuOo7QES1kkv6OLmp5ze2XBZQIVffM=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
-github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 h1:CyuI+igIjadM/GRnE2o0q+WCwipDh0n2cUYFPAvxziM=
-github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657/go.mod h1:JRiumF+RFsH1mrrP8FUsi9tExPylKkO/oSRWeQEUdLE=
+github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f h1:onZ3oc6l1Gz8pVpQ0c1U1Cb11kIMoDb3xtEy/iZbYZM=
+github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
+github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
+github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
+github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
+github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig=
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/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
+github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
-github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
-github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
-github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk=
-github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
+github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E=
+github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
+github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU=
+github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE=
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 v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk=
-github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM=
-github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
-github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
-github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
-github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8=
-github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
-github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
+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.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/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA=
+github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c=
+github.com/cometbft/cometbft v0.37.5 h1:/U/TlgMh4NdnXNo+YU9T2NMCWyhXNDF34Mx582jlvq0=
+github.com/cometbft/cometbft v0.37.5/go.mod h1:QC+mU0lBhKn8r9qvmnq53Dmf3DWBt4VtkcKw2C81wxY=
+github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo=
+github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0=
+github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4=
+github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak=
+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/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
+github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
+github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
+github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
+github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44=
-github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU=
-github.com/cosmos/cosmos-proto v1.0.0-alpha8 h1:d3pCRuMYYvGA5bM0ZbbjKn+AoQD4A7dyNG2wzwWalUw=
-github.com/cosmos/cosmos-sdk v0.45.11 h1:Pc44fFEkai0KXFND5Ys/2ZJkfVdstMIBzKBN8MY7Ll0=
-github.com/cosmos/cosmos-sdk v0.45.11/go.mod h1:45z8Q1Ah4iypFycu2Kl4kBPIsQKUiND8G2CUX+HTtPM=
+github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk=
+github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis=
+github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
+github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
+github.com/cosmos/cosmos-sdk v0.47.11 h1:0Qx7eORw0RJqPv+mvDuU8NQ1LV3nJJKJnPoYblWHolc=
+github.com/cosmos/cosmos-sdk v0.47.11/go.mod h1:ADjORYzUQqQv/FxDi0H0K5gW/rAk1CiDR3ZKsExfJV0=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
-github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI=
-github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y=
-github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw=
-github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok=
-github.com/cosmos/ibc-go/v4 v4.2.0 h1:Fx/kKq/uvawrAxk6ZrQ6sEIgffLRU5Cs/AUnvpPBrHI=
-github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
-github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
-github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
-github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
+github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
+github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI=
+github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g=
+github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y=
+github.com/cosmos/iavl v0.20.1 h1:rM1kqeG3/HBT85vsZdoSNsehciqUQPWrR4BYmqE2+zg=
+github.com/cosmos/iavl v0.20.1/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A=
+github.com/cosmos/ibc-go/v7 v7.3.1 h1:bil1IjnHdyWDASFYKfwdRiNtFP6WK3osW7QFEAgU4I8=
+github.com/cosmos/ibc-go/v7 v7.3.1/go.mod h1:wvx4pPBofe5ZdMNV3OFRxSI4auEP5Qfqf8JXLLNV04g=
+github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM=
+github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0=
+github.com/cosmos/ledger-cosmos-go v0.12.4 h1:drvWt+GJP7Aiw550yeb3ON/zsrgW0jgh5saFCr7pDnw=
+github.com/cosmos/ledger-cosmos-go v0.12.4/go.mod h1:fjfVWRf++Xkygt9wzCsjEBdjcf7wiiY35fv3ctT+k4M=
+github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM=
+github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4=
+github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
+github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
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/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/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/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8=
+github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
-github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e h1:5jVSh2l/ho6ajWhSPNN84eHEdq3dp0T7+f6r3Tc6hsk=
+github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8=
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/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4=
-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/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
-github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+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.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
+github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE=
+github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
+github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
+github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI=
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo=
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o=
-github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
-github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
-github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
-github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
-github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
+github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
-github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA=
+github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg=
+github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
+github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
+github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
+github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
+github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v25.0.2+incompatible h1:/OaKeauroa10K4Nqavw4zlhcDq/WBcPMc5DbjOGgozY=
+github.com/docker/docker v25.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dontpanicdao/caigo v0.4.0 h1:S0wRKh2EZ9qj6IfHZIGXxiJF37emRCqnZwDhRb1+DJ4=
-github.com/dontpanicdao/caigo v0.4.0/go.mod h1:1YuwgcVLODaS/n0vfuYN/Q0mdWs8UDfDMkSpUdkKXD4=
-github.com/duo-labs/webauthn v0.0.0-20210727191636-9f1b88ef44cc h1:mLNknBMRNrYNf16wFFUyhSAe1tISZN7oAfal4CZ2OxY=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo=
+github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
-github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo=
+github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
-github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
-github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
-github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
+github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
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/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
+github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
-github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ=
-github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
-github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
+github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
+github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA=
+github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk=
+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.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg=
+github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
-github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
-github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
-github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
-github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
+github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM=
+github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
-github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
-github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
-github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as=
-github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
+github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
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/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
-github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
-github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
-github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
-github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
-github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0=
-github.com/gagliardetto/binary v0.7.1 h1:6ggDQ26vR+4xEvl/S13NcdLK3MUCi4oSy73pS9aI1cI=
-github.com/gagliardetto/binary v0.7.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
+github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY=
+github.com/gagliardetto/binary v0.7.7/go.mod h1:mUuay5LL8wFVnIlecHakSZMvcdqfs+CsotR5n77kyjM=
+github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw=
github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY=
-github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 h1:q2IztKyRQUxJ6abXRsawaBtvDFvM+szj4jDqV4od1gs=
-github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY=
+github.com/gagliardetto/solana-go v1.8.4 h1:vmD/JmTlonyXGy39bAo0inMhmbdAwV7rXZtLDMZeodE=
+github.com/gagliardetto/solana-go v1.8.4/go.mod h1:i+7aAyNDTHG0jK8GZIBSI4OVvDqkt2Qx+LklYclRNG8=
github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw=
github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
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/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ=
-github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
-github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM=
-github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE=
+github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM=
+github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE=
+github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
+github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
+github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI=
github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w=
+github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw=
github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE=
github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY=
-github.com/gin-contrib/size v0.0.0-20220707104239-f5a650759656 h1:IxCENnXjmppSWzMedenibLt8tvKg4b7kQ7lTGjGjsgw=
-github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 h1:Z9J0PVIt1PuibOShaOw1jH8hUYz+Ak8NLsR/GI0Hv5I=
+github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4/go.mod h1:CEPcgZiz8998l9E8fDm16h8UfHRL7b+5oG0j/0koeVw=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
-github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
-github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
+github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg=
+github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
+github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
-github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
+github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
-github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
+github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
+github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc=
+github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
+github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
+github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M=
+github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
+github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
+github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
+github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
+github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro=
+github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw=
+github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
+github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
+github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
+github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
+github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
+github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k=
+github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
-github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
-github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
-github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
-github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
-github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
-github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU=
+github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
+github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
+github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
+github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
-github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
-github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
+github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g=
+github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw=
+github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0=
+github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY=
+github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
+github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.4/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/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
-github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
-github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0=
+github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
+github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
-github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg=
+github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU=
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/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
+github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
+github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
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=
@@ -433,6 +651,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -449,21 +668,21 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
-github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
-github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
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=
@@ -477,23 +696,23 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg=
+github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk=
+github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
-github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
-github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
-github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
-github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
+github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -501,47 +720,79 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
-github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/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=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
+github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
+github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
+github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs=
+github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
+github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=
-github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
-github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
-github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
-github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
-github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
+github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
+github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
+github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-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/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f h1:gyojr97YeWZ70pKNakWv5/tKwBHuLy3icnIeCo9gQr4=
+github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f/go.mod h1:8dsy5tQOkeNQyjXpm5mQsbCu3H5uzeBD35MzRQFznKU=
+github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPftShATouOrBVy6GaTTjgQd/VfNiZp/VXQ=
+github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU=
+github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240326122733-6f96a993222b h1:Msqs1nc2qWMxTriDCITKl58Td+7Md/RURmUmH7RXKns=
+github.com/grafana/grafana-foundation-sdk/go v0.0.0-20240326122733-6f96a993222b/go.mod h1:WtWosval1KCZP9BGa42b8aVoJmVXSg0EvQXi9LDSVZQ=
+github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 h1:gdrsYbmk8822v6qvPwZO5DC6QjnAW7uKJ9YXnoUmV8c=
+github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503/go.mod h1:d8seWXCEXkL42mhuIJYcGi6DxfehzoIpLrMQWJojvOo=
+github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeebhJIBkgYOD06Mxk9HV2KhtEG0hp/7R+5RUQ=
+github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0=
+github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
+github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
+github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
+github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug=
+github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4=
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-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
+github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
+github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
+github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
@@ -549,116 +800,115 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
-github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
-github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
+github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8=
+github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A=
+github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A=
+github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
+github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
+github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
+github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY=
+github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
+github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
-github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM=
+github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99 h1:OSQYEsRT3tRttZkk6zyC3aAaliwd7Loi/KgXgXxGtwA=
+github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
+github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
+github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
+github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
-github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
-github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
+github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
+github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
+github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0=
+github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
-github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfviiAgIUjg2PXxsQfs5bphsG8F7Keo=
-github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU=
-github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE=
+github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY=
+github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
+github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU=
+github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
+github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok=
+github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0=
+github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw=
+github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
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.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
-github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
+github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
+github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
-github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
-github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
-github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
-github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
+github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
+github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
+github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw=
+github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
+github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+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/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
-github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
-github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
+github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
+github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
-github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
-github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
-github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
-github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
-github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
-github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
-github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=
-github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
-github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
-github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
-github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
-github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
-github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
-github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
-github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg=
-github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=
-github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
-github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
-github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
-github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
-github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
-github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE=
-github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk=
-github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
-github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
-github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
-github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
-github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
-github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
-github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
-github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
-github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=
-github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=
-github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
-github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
-github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
-github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY=
-github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=
-github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
-github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
-github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
-github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0=
-github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
-github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
+github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
+github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4=
+github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@@ -669,8 +919,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q=
-github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
+github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
+github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
@@ -686,8 +936,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
-github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
+github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
@@ -701,78 +951,70 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
-github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
-github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
+github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
-github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
-github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
-github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc=
-github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
-github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
-github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
-github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
-github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
-github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
-github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
-github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
+github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
-github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
-github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
-github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
+github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
+github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
-github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
-github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
-github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
-github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
-github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
-github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
+github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
+github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
-github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
-github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
+github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
+github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
-github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o=
-github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -781,305 +1023,122 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
-github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU=
github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
-github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
+github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE=
-github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
-github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
-github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=
-github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
-github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
-github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
-github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
-github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=
-github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M=
-github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU=
-github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
-github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc=
-github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8=
-github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
-github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
-github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
-github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
-github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54=
-github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k=
-github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
-github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
-github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
-github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s=
-github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo=
-github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
-github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU=
-github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
-github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
-github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=
-github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI=
-github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A=
-github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug=
-github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk=
-github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=
-github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=
-github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk=
-github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=
-github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=
-github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo=
-github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc=
-github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA=
-github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
-github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=
-github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
-github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
-github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
-github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
-github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
-github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII=
-github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
-github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
-github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
-github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
-github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y=
-github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM=
-github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
-github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
-github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
-github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
-github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
-github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
-github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw=
-github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
-github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
-github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
-github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=
-github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
-github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
-github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc=
-github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI=
-github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70=
-github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk=
-github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
-github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
-github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
-github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
-github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
-github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
-github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
-github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw=
-github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
-github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
-github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
-github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU=
-github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw=
-github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ=
-github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
-github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM=
-github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk=
-github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE=
-github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
-github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
-github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
-github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
-github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ=
-github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
-github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA=
-github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
-github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw=
-github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
-github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
-github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
-github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
-github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0=
-github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4=
-github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
-github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
-github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
-github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
-github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY=
-github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=
-github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=
-github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM=
-github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
-github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
-github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
-github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA=
-github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw=
-github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
-github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
-github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
-github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
-github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
-github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
-github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=
-github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ=
-github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0=
-github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
-github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
-github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
-github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
-github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
-github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI=
-github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s=
-github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
-github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw=
-github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA=
-github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=
-github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
-github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=
-github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po=
-github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0=
-github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4=
-github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
-github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
-github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=
-github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
-github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
-github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
-github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
-github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
-github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU=
-github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
-github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
-github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
-github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA=
-github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
-github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
-github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q=
-github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=
-github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
-github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
-github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo=
-github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
-github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=
-github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
-github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
-github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU=
-github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
-github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
-github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM=
-github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM=
-github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw=
-github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
-github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0=
-github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
-github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
-github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=
-github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=
-github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=
-github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=
-github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=
-github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0=
-github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns=
-github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M=
-github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
-github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
-github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
-github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k=
-github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA=
-github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
-github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
-github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
-github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
-github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
-github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
-github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
-github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU=
-github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU=
+github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg=
+github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8=
+github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
-github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
+github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U=
+github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f/go.mod h1:Z60vy0EZVSu0bOugCHdcN5ZxFMKSpjRgsnh0XKPFqqk=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
+github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
-github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
-github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
-github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
+github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
+github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
-github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
+github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
+github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
+github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94=
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
-github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
-github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
-github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
-github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
-github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
-github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
-github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
+github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
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/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+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/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
+github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
+github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
+github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
+github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -1089,280 +1148,313 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
+github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk=
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE=
-github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
-github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
-github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
-github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
-github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
-github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
-github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
-github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
-github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
-github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
-github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
-github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
-github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
-github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
-github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
-github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
-github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
-github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
-github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
-github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs=
-github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0=
-github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
-github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
-github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=
-github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
-github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
-github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
-github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
-github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
-github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
-github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
-github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=
-github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
-github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
-github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA=
-github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk=
-github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA=
-github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
-github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
-github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
-github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
-github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
-github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
-github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
-github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
-github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
-github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I=
-github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
-github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
-github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
-github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
-github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo=
-github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs=
-github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
-github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
-github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
-github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
-github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
-github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
-github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=
+github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
+github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/ginkgo/v2 v2.5.1 h1:auzK7OI497k6x4OvWq+TKAcpcSAlod0doAH72oIN0Jw=
-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.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI=
+github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
-github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
-github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
-github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
-github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
+github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
+github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40=
+github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M=
+github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg=
+github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo=
+github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
+github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
-github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
+github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
+github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
+github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
+github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
+github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
+github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0=
+github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
-github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
+github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU=
+github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
+github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
+github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/pressly/goose/v3 v3.5.3 h1:lIQIIXVbdO2RuQtJBS1e7MZjKEk0demVWt6i0YPiOrg=
-github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
-github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
+github.com/pressly/goose/v3 v3.21.1 h1:5SSAKKWej8LVVzNLuT6KIvP1eFDuPvxa+B6H0w78buQ=
+github.com/pressly/goose/v3 v3.21.1/go.mod h1:sqthmzV8PitchEkjecFJII//l43dLOCzfWh8pHEe+vE=
+github.com/prometheus/alertmanager v0.26.0 h1:uOMJWfIwJguc3NaM3appWNbbrh6G/OjvaHMk22aBBYc=
+github.com/prometheus/alertmanager v0.26.0/go.mod h1:rVcnARltVjavgVaNnmevxK7kOn7IZavyf0KNgHkbEpU=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
+github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
-github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
-github.com/pyroscope-io/client v0.7.0 h1:LWuuqPQ1oa6x7BnmUOuo/aGwdX85QGhWZUBYWWW3zdk=
-github.com/pyroscope-io/client v0.7.0/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU=
-github.com/pyroscope-io/godeltaprof v0.1.0 h1:UBqtjt0yZi4jTxqZmLAs34XG6ycS3vUTlhEUSq4NHLE=
-github.com/pyroscope-io/godeltaprof v0.1.0/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0=
+github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
+github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4=
+github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI=
+github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 h1:oHcfzdJnM/SFppy2aUlvomk37GI33x9vgJULihE5Dt8=
+github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+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/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk=
+github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw=
+github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU=
+github.com/pyroscope-io/godeltaprof v0.1.2 h1:MdlEmYELd5w+lvIzmZvXGNMVzW2Qc9jDMuJaPOR75g4=
+github.com/pyroscope-io/godeltaprof v0.1.2/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
+github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
-github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg=
+github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4=
github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
+github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
-github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
-github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
+github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
+github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
-github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
+github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ=
github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
+github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
+github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY=
+github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ=
+github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
+github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
+github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
+github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/shirou/gopsutil/v3 v3.22.12 h1:oG0ns6poeUSxf78JtOsfygNWuEHYYz8hnnNg7P04TJs=
-github.com/shirou/gopsutil/v3 v3.22.12/go.mod h1:Xd7P1kwZcp5VW52+9XsirIKd/BROzbb2wdX3Kqlz9uI=
+github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
+github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ=
github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
-github.com/goplugin/plugin-cosmos v0.1.7-0.20230424184432-20550926ba07 h1:LBjS7F3Xy9jYlgiEMMMU5f+i/v7oZ97MYseyF6aY7ts=
-github.com/goplugin/plugin-env v0.3.29 h1:hcIw/BeuB0wKiiE3umAUNBZzWkHO24XF3OW9xSrlMbI=
-github.com/goplugin/plugin-env v0.3.29/go.mod h1:9c0Czq4a6wZKY20BcoAlK29DnejQIiLo/MwKYtSFnHk=
-github.com/goplugin/plugin-relay v0.1.7-0.20230424181359-6cb4dc745ec7 h1:uLPs52VF4VLmNCeC4T398nAVjcmS1KIzt6ZK6iERZ/4=
-github.com/goplugin/plugin-relay v0.1.7-0.20230424181359-6cb4dc745ec7/go.mod h1:3E3PXaMEl2gADk/DTkbOxsvtpDcJ5ZSyW+vt0TjsEH0=
-github.com/goplugin/plugin-solana v1.0.3-0.20230424191709-c9fec8c08e1b h1:CJIPaIwlmV5GFSf9Of1Qnpud3gBAeRiT049IiZNzR2g=
-github.com/goplugin/plugin-testing-framework v1.11.5 h1:gYSnOQhLxgE0mxwnv015nNnPgH9kcosx+AzPboEFo38=
-github.com/goplugin/plugin-testing-framework v1.11.5/go.mod h1:0ktPcDE5fFSvNewsaHuC4tGVaiCMQsl5RN/cWO5k0rg=
-github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20230420131147-ce3c53a39d07 h1:UW3llKpFIfVmtu5F1GDLz0S4cze9Un46k15M+JDXSCU=
-github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20230420131147-ce3c53a39d07/go.mod h1:dvEXSlzknoPm6YFaa0Ubs57CPFjhBbXnMju7WgiqiD4=
-github.com/goplugin/pluginv3.0/v2 v2.1.0-beta0.0.20230427051455-edb338fd2536 h1:uomhVY2qYciWK0XuFqEpqbKdVmYAFQCDw6Lg8L8Hrt0=
-github.com/goplugin/pluginv3.0/v2 v2.1.0-beta0.0.20230427051455-edb338fd2536/go.mod h1:adNwYzBQKE0gRgebDch8E0Iu5ke0/PmoRCQe638cjSw=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc h1:aSCDAai0Dmbhp/KHTtJnC/EJcaEz4CAO80SKRzRZiQA=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc/go.mod h1:5JnCHuYgmIP9ZyXzgAfI5Iwu0WxBtBKp+ApeT5o1Cjw=
-github.com/smartcontractkit/ocr2keepers v0.6.14 h1:Rg+SYd8PCyd4CcCetwnRKjVEQsHVsV6QOaWcLhi+6sg=
-github.com/smartcontractkit/ocr2keepers v0.6.14/go.mod h1:gqIksJFzdXFsHfGdCWm1uTxbwvAltgcwcaqIgAStC1A=
-github.com/smartcontractkit/ocr2vrf v0.0.0-20230425184732-a793ac75f0a3 h1:K71txN76a7Tf9teLEpoxsMhWXi36W2gDeicLqqa6/p0=
-github.com/smartcontractkit/ocr2vrf v0.0.0-20230425184732-a793ac75f0a3/go.mod h1:NKkp8yf3trq+hJe/gn2Q1dd4abZvcYavUKPzYJCgVew=
-github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A=
-github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb/go.mod h1:HNUu4cJekUdsJbwRBCiOybtkPJEfGRELQPe2tkoDEyk=
-github.com/goplugin/wsrpc v0.6.2-0.20230317160629-382a1ac921d8 h1:Wn9X8mOQoQzzh1kBK22EDDgyXAfVjDlFlqUQW5kyyGo=
-github.com/goplugin/wsrpc v0.6.2-0.20230317160629-382a1ac921d8/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0=
+github.com/goplugin/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnjjIQAEBnutCtksPzVDY=
+github.com/goplugin/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
+github.com/goplugin/plugin-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8=
+github.com/goplugin/plugin-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM=
+github.com/goplugin/plugin-ccip v0.0.0-20240911145028-d346e3ace978 h1:BPuehkAQ8R112SlTitukSdKYRJMY3zkvaQS4VSTNn0Q=
+github.com/goplugin/plugin-ccip v0.0.0-20240911145028-d346e3ace978/go.mod h1:X1f4CKlR1RilSgzArQv5HNvMrVSt+Zloihm3REwxhdQ=
+github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b h1:eW1CSdNcDtOFqjrtfR93KTg80rHP+WWh5UybdJcdU8M=
+github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc=
+github.com/goplugin/plugin-cosmos v0.4.1-0.20240911160024-c1da28250122 h1:gwOmVJgLJZzc41wb+TkNfZEvsm2hS5j2pcF2dwCiL8Y=
+github.com/goplugin/plugin-cosmos v0.4.1-0.20240911160024-c1da28250122/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo=
+github.com/goplugin/plugin-data-streams v0.0.0-20240906125718-9f0a98d32fbc h1:tRmTlaoAt+7FakMXXgeCuRPmzzBo5jsGpeCVvcU6KMc=
+github.com/goplugin/plugin-data-streams v0.0.0-20240906125718-9f0a98d32fbc/go.mod h1:PwPcmQNAzVmU8r8JWKrDRgvXesDwxnqbMD6DvYt/Z7M=
+github.com/goplugin/plugin-feeds v0.0.0-20240910155501-42f20443189f h1:p4p3jBT91EQyLuAMvHD+zNJsuAYI/QjJbzuGUJ7wIgg=
+github.com/goplugin/plugin-feeds v0.0.0-20240910155501-42f20443189f/go.mod h1:FLlWBt2hwiMVgt9AcSo6wBJYIRd/nsc8ENbV1Wir1bw=
+github.com/goplugin/plugin-solana v1.1.1-0.20240911160840-cde14abca28e h1:UEP+7EDuFI4gRcb5uX0pC4jacpw71w6ctUu3TNewFOs=
+github.com/goplugin/plugin-solana v1.1.1-0.20240911160840-cde14abca28e/go.mod h1:iJ9DKYo0F64ue7IogAIELwU2DfrhEAh76eSmZOilT8A=
+github.com/goplugin/plugin-testing-framework v1.33.0 h1:vHQODEdsq5AIbRiyZZ30de6uwJUNFXLYvCr+Odr8TIs=
+github.com/goplugin/plugin-testing-framework v1.33.0/go.mod h1:GrhHthZ5AmceF82+Ypw6Fov1EvB05JJbb1T0EKyO1x0=
+github.com/goplugin/plugin-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 h1:Kk5OVlx/5g9q3Z3lhxytZS4/f8ds1MiNM8yaHgK3Oe8=
+github.com/goplugin/plugin-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU=
+github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20240708135824-bf9122a8cee6 h1:oxyhjC53wA3B8WG4TbRcIO/WCw9jzSFRzwQQ9QGbSck=
+github.com/goplugin/pluginv3.0/integration-tests v0.0.0-20240708135824-bf9122a8cee6/go.mod h1:+lAHs46edxC7o1bURJBQ81rR/ej6PYCGU8l8dOgNRnM=
+github.com/goplugin/pluginv3.0/v2 v2.14.0-mercury-20240807.0.20240911170808-18cc10abf094 h1:ocdKkyQh2zVH4GrEkQgU5W+CqaZBfZxjjfd8adly3dM=
+github.com/goplugin/pluginv3.0/v2 v2.14.0-mercury-20240807.0.20240911170808-18cc10abf094/go.mod h1:zmzbErOMN3cCGMY4EpvXngky4hIly5cDXX65tLTC5CA=
+github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs=
+github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA=
+github.com/goplugin/plugin-libocr v0.0.0-20240717100443-f6226e09bee7 h1:e38V5FYE7DA1JfKXeD5Buo/7lczALuVXlJ8YNTAUxcw=
+github.com/goplugin/plugin-libocr v0.0.0-20240717100443-f6226e09bee7/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
+github.com/goplugin/seth v1.0.12 h1:iVdgMx42XWanPPnBaM5StR4c1XsTr/0/B/kKRZL5BsY=
+github.com/goplugin/seth v1.0.12/go.mod h1:thWtbLyW4nRHJGzC5heknQDORoJPErE15sF34LHkorg=
+github.com/goplugin/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 h1:yiKnypAqP8l0OX0P3klzZ7SCcBUxy5KqTAKZmQOvSQE=
+github.com/goplugin/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:q6f4fe39oZPdsh1i57WznEZgxd8siidMaSFq3wdPmVg=
+github.com/goplugin/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 h1:Dai1bn+Q5cpeGMQwRdjOdVjG8mmFFROVkSKuUgBErRQ=
+github.com/goplugin/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1/go.mod h1:G5Sd/yzHWf26rQ+X0nG9E0buKPqRGPMJAfk2gwCzOOw=
+github.com/goplugin/wasp v0.4.7 h1:7mKJfwzFbuE8xVLUYtLt7Bjw8q/bmVZRW6Ks8kc1LVM=
+github.com/goplugin/wasp v0.4.7/go.mod h1:jeabvyXikb2aNoLQwcZGqaz17efrR8NJhpq4seAmdgs=
+github.com/goplugin/wsrpc v0.8.2 h1:XB/xcn/MMseHW+8JE8+a/rceA86ck7Ur6cEa9LiUC8M=
+github.com/goplugin/wsrpc v0.8.2/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
-github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
-github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
+github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
+github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
-github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
-github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
+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.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
-github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
-github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75 h1:ZqpS7rAhhKD7S7DnrpEdrnW1/gZcv82ytpMviovkli4=
+github.com/streamingfast/logging v0.0.0-20220405224725-2755dab2ce75/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -1373,116 +1465,130 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
-github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
-github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
-github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
-github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
-github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
-github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
-github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
-github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI=
-github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+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/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
+github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
-github.com/tendermint/tendermint v0.34.23 h1:JZYsdc59aOiT5efou+BHILJv8x6FlRyvlor84Xq9Tb0=
-github.com/tendermint/tendermint v0.34.23/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI=
-github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8=
-github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I=
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 h1:3SNcvBmEPE1YlB1JpVZouslJpI3GBNoiqW7+wb0Rz7w=
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
+github.com/testcontainers/testcontainers-go v0.28.0 h1:1HLm9qm+J5VikzFDYhOd+Zw12NtOl+8drH2E8nTY1r8=
+github.com/testcontainers/testcontainers-go v0.28.0/go.mod h1:COlDpUXbwW3owtpMkEB1zo9gwb1CoKVKlyrVPejF4AU=
github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a h1:YuO+afVc3eqrjiCUizNCxI53bl/BnPiVwXqLzqYTqgU=
github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47zCZp9FrtGcWyo1VjbgDaodxX9ovZvgLb/MxaA=
+github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
+github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
-github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
-github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
+github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
-github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
-github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
-github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
-github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+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/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
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/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
+github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
+github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/ulule/limiter/v3 v3.11.1 h1:wm6YaA2JwIXc0S+z8TK8/neWMOTf4m20I5jL1dwLRcw=
+github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
+github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA=
+github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI=
github.com/umbracle/ethgo v0.1.3 h1:s8D7Rmphnt71zuqrgsGTMS5gTNbueGO1zKLh7qsFzTM=
github.com/umbracle/ethgo v0.1.3/go.mod h1:g9zclCLixH8liBI27Py82klDkW7Oo33AxUOr+M9lzrU=
github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 h1:10Nbw6cACsnQm7r34zlpJky+IzxVLRk6MKTS2d3Vp0E=
github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722/go.mod h1:c8J0h9aULj2i3umrfyestM6jCq0LK0U6ly6bWy96nd4=
-github.com/unrolled/secure v0.0.0-20190624173513-716474489ad3 h1:Is9lt18DCzmbgaXowC/LuO1prTus8ejfgMn+GelBuHs=
-github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8=
-github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
-github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk=
+github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
+github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
+github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
+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/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
github.com/valyala/fastjson v1.4.1 h1:hrltpHpIpkaxll8QltMU8c3QZ5+qIiCL8yKqPFJI/yE=
github.com/valyala/fastjson v1.4.1/go.mod h1:nV6MsjxL2IMJQUoHDIrjEI7oLyeqK6aBD7EFWPsvP8o=
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=
-github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
-github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
-github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
-github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
-github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE=
-github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
-github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
-github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
-github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
-github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
+github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
+github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
-github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
+github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
+github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
-github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
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=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
-github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
+github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8=
-github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
+github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U=
+github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
+github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw=
+github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI=
go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=
go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg=
-go.dedis.ch/kyber/v3 v3.0.14 h1:vnHb/Q5ape/e98oYZdbOrs3CkQ1bUIZFANmOxb/3zyo=
-go.dedis.ch/kyber/v3 v3.0.14/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U=
+go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0=
+go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U=
go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
-go.dedis.ch/protobuf v1.0.11 h1:FTYVIEzY/bfl37lu3pR4lIj+F9Vp1jE8oh91VmxKgLo=
go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
-go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
+go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
+go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
+go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
+go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
+go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
+go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
+go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
+go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
+go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
+go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
+go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
+go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
+go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
@@ -1492,76 +1598,112 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g=
-go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk=
+go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE=
+go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg=
+go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8=
+go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw=
+go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg=
+go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
+go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
+go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9 h1:UiRNKd1OgqsLbFwE+wkAWTdiAxXtCBqKIHeBIse4FUA=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9/go.mod h1:eqZlW3pJWhjyexnDPrdQxix1pn0wwhI4AO4GKpP/bMI=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0 h1:0MH3f8lZrflbUWXVxyBg/zviDFdGE062uKh5+fu8Vv0=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0/go.mod h1:Vh68vYiHY5mPdekTr0ox0sALsqjoVy0w3Os278yX5SQ=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0 h1:BJee2iLkfRfl9lc7aFmBwkWxY/RI1RDdXepSF6y8TPE=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0/go.mod h1:DIzlHs3DRscCIBU3Y9YSzPfScwnYnzfnCd4g8zA7bZc=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bEkIYOVMw4q1WJxIAGoFTrtYOzWuRQ=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y=
+go.opentelemetry.io/otel/log v0.4.0 h1:/vZ+3Utqh18e8TPjuc3ecg284078KWrR8BRz+PQAj3o=
+go.opentelemetry.io/otel/log v0.4.0/go.mod h1:DhGnQvky7pHy82MIRV43iXh3FlKN8UUKftn0KbLOq6I=
+go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
+go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
+go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/sdk/log v0.4.0 h1:1mMI22L82zLqf6KtkjrRy5BbagOTWdJsqMY/HSqILAA=
+go.opentelemetry.io/otel/sdk/log v0.4.0/go.mod h1:AYJ9FVF0hNOgAVzUG/ybg/QttnXhUePWAupmCqtdESo=
+go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
+go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
+go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
+go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
+go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
-go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=
+go.uber.org/ratelimit v0.3.0 h1:IdZd9wqvFXnvLvSEBo0KPcGfkoBGNkpTHlrE3Rcjkjw=
+go.uber.org/ratelimit v0.3.0/go.mod h1:So5LG7CV1zWpY1sHe+DXTJqQvOx+FFPFaAs2SnoyBaI=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
-go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
-go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
-go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s=
+go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
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=
@@ -1572,8 +1714,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1587,8 +1729,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -1597,25 +1737,21 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-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.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
-golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -1625,7 +1761,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -1642,43 +1778,41 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
-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.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
-golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
+golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1686,30 +1820,29 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/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-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1718,6 +1851,7 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1725,6 +1859,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1738,52 +1873,63 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
-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.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
+golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
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=
@@ -1793,41 +1939,44 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
+golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1852,26 +2001,19 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
-golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
-golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1879,10 +2021,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
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=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
-gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
-gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o=
-gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
+gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
+gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
+gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -1900,9 +2042,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
-google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
-google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw=
+google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1910,7 +2051,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -1937,6 +2077,7 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@@ -1946,17 +2087,13 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
-google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 h1:znp6mq/drrY+6khTAlJUDNFFcDGV2ENLYKpMq8SyCds=
-google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
+google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d h1:/hmn0Ku5kWij/kjGsrcJeC1T/MrJi2iNWwgAqrihFwc=
+google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
+google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
+google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1969,20 +2106,14 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
-google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
-google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
-google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
-google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
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=
@@ -1995,39 +2126,29 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
-gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
-gopkg.in/guregu/null.v2 v2.1.2 h1:YOuepWdYqGnrenzPyMi+ybCjeDzjdazynbwsXXOk4i8=
gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg=
gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
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/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-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/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+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/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
-gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@@ -2035,20 +2156,20 @@ 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=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
-gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
+gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2056,38 +2177,47 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
-k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
-k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k=
-k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo=
-k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
-k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
-k8s.io/cli-runtime v0.25.4 h1:GTSBN7aKBrc2LqpdO30CmHQqJtRmotxV7XsMSP+QZIk=
-k8s.io/cli-runtime v0.25.4/go.mod h1:JGOw1CR8v4Mcz6cEKA7bFQe0bPrNn1l5sGAX1/Ke4Eg=
-k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8=
-k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
-k8s.io/component-base v0.25.4 h1:n1bjg9Yt+G1C0WnIDJmg2fo6wbEU1UGMRiQSjmj7hNQ=
-k8s.io/component-base v0.25.4/go.mod h1:nnZJU8OP13PJEm6/p5V2ztgX2oyteIaAGKGMYb2L2cY=
-k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
-k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
-k8s.io/kubectl v0.25.4 h1:O3OA1z4V1ZyvxCvScjq0pxAP7ABgznr8UvnVObgI6Dc=
-k8s.io/kubectl v0.25.4/go.mod h1:CKMrQ67Bn2YCP26tZStPQGq62zr9pvzEf65A0navm8k=
-k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
-k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
+k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
+k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg=
+k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU=
+k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg=
+k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
+k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
+k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk=
+k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA=
+k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
+k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY=
+k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E=
+k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc=
+k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
+k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
+k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
+k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM=
+k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
+nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
+nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
+pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
+pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ=
-sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
-sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
-sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
-sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
-sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
-sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
-sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
+rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
+sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU=
+sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
+sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
+sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
+sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
+sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
+sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/integration-tests/infra_deployments/deployer_test.go b/integration-tests/infra_deployments/deployer_test.go
deleted file mode 100644
index a349f90..0000000
--- a/integration-tests/infra_deployments/deployer_test.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package infra_deployments_test
-
-import (
- "fmt"
- "net/url"
- "testing"
-
- "github.com/goplugin/plugin-starknet/integration-tests/common"
- "github.com/goplugin/plugin-starknet/ops/gauntlet"
- "github.com/goplugin/plugin-starknet/ops/utils"
- "github.com/goplugin/pluginv3.0/integration-tests/client"
- "github.com/stretchr/testify/require"
-)
-
-const (
- L2RpcUrl = "https://alpha4-2.starknet.io"
- P2pPort = "5001"
-)
-
-var (
- observationSource = `
- val [type="bridge" name="bridge-coinmetrics" requestData=<{"data": {"from":"PLI","to":"USD"}}>]
- parse [type="jsonparse" path="result"]
- val -> parse
- `
- juelsPerFeeCoinSource = `"""
- sum [type="sum" values=<[451000]> ]
- sum
- """
- `
-)
-
-func createKeys(testState *testing.T) ([]*client.Plugin, error) {
- urls := [][]string{
- // Node access params
- {"NODE_URL", "NODE_USER", "NODE_PASS"},
- }
- var clients []*client.Plugin
-
- for _, nodeUrl := range urls {
- u, _ := url.Parse(nodeUrl[0])
- c, err := client.NewPlugin(&client.PluginConfig{
- URL: nodeUrl[0],
- Email: nodeUrl[1],
- Password: nodeUrl[2],
- RemoteIP: u.Host,
- })
- if err != nil {
- return nil, err
- }
- key, _ := c.MustReadP2PKeys()
- if key == nil {
- _, _, err = c.CreateP2PKey()
- require.NoError(testState, err)
- }
- clients = append(clients, c)
- }
- return clients, nil
-}
-func TestOCRBasic(testState *testing.T) {
- var err error
- t := &common.Test{}
- t.Common = common.New()
- t.Common.Default(testState)
- t.Cc = &common.PluginClient{}
- t.Common.P2PPort = P2pPort
- t.Cc.PluginNodes, err = createKeys(testState)
- require.NoError(testState, err)
- t.Cc.NKeys, _, err = client.CreateNodeKeysBundle(t.Cc.PluginNodes, t.Common.ChainName, t.Common.ChainId)
- require.NoError(testState, err)
- for _, n := range t.Cc.PluginNodes {
- _, _, err = n.CreateStarkNetChain(&client.StarkNetChainAttributes{
- Type: t.Common.ChainName,
- ChainID: t.Common.ChainId,
- Config: client.StarkNetChainConfig{},
- })
- require.NoError(testState, err)
- _, _, err = n.CreateStarkNetNode(&client.StarkNetNodeAttributes{
- Name: t.Common.ChainName,
- ChainID: t.Common.ChainId,
- Url: L2RpcUrl,
- })
- require.NoError(testState, err)
- }
- t.Common.Testnet = true
- t.Common.L2RPCUrl = L2RpcUrl
- t.Sg, err = gauntlet.NewStarknetGauntlet(fmt.Sprintf("%s/", utils.ProjectRoot))
- require.NoError(testState, err, "Could not get a new gauntlet struct")
- err = t.Sg.SetupNetwork(t.Common.L2RPCUrl)
- require.NoError(testState, err, "Setting up gauntlet network should not fail")
- err = t.DeployGauntlet(0, 100000000000, 9, "auto", 1, 1)
- require.NoError(testState, err, "Deploying contracts should not fail")
- t.SetBridgeTypeAttrs(&client.BridgeTypeAttributes{
- Name: "bridge-coinmetrics",
- URL: "ADAPTER_URL", // ADAPTER_URL e.g https://adapters.main.sand.cldev.sh/coinmetrics
- })
-
- err = t.Common.CreateJobsForContract(t.Cc, observationSource, juelsPerFeeCoinSource, t.OCRAddr, t.AccountAddresses)
- require.NoError(testState, err)
-}
diff --git a/integration-tests/package.json b/integration-tests/package.json
index c2725fe..9de3f3d 100644
--- a/integration-tests/package.json
+++ b/integration-tests/package.json
@@ -1,5 +1,5 @@
{
- "name": "@pluginv3.0/starknet-integration-tests",
+ "name": "@plugin/starknet-integration-tests",
"version": "0.0.1",
"license": "MIT",
"dependencies": {},
diff --git a/integration-tests/scripts/buildTests b/integration-tests/scripts/buildTests
index 6c9731b..ed2ec11 100755
--- a/integration-tests/scripts/buildTests
+++ b/integration-tests/scripts/buildTests
@@ -8,6 +8,8 @@ set -ex
# get this scripts directory
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
+helm repo update
+
cd "$SCRIPT_DIR"/../../ || exit 1
# integration prep
diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint
index 94ea19c..462aaaf 100755
--- a/integration-tests/scripts/entrypoint
+++ b/integration-tests/scripts/entrypoint
@@ -14,4 +14,5 @@ cd "$SCRIPT_DIR"/../ || exit 1
# SUITE=${SUITE:=} the suite of tests you want to run
# TEST_NAME=${TEST_NAME:=} The specific test to run
# run the tests
+nix develop -c helm repo update
nix develop -c ./"${SUITE}".test -test.v -test.count 1 ${ARGS} -test.run ^${TEST_NAME}$
diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go
index 934eb46..e2a9530 100644
--- a/integration-tests/smoke/ocr2_test.go
+++ b/integration-tests/smoke/ocr2_test.go
@@ -1,64 +1,89 @@
package smoke_test
-// revive:disable:dot-imports
import (
"flag"
"fmt"
- "github.com/goplugin/pluginv3.0/integration-tests/actions"
- "go.uber.org/zap/zapcore"
+ "maps"
+ "os"
"testing"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/goplugin/plugin-testing-framework/logging"
+ "github.com/goplugin/pluginv3.0/integration-tests/actions"
+ "github.com/goplugin/pluginv3.0/integration-tests/docker/test_env"
+
"github.com/goplugin/plugin-starknet/integration-tests/common"
+ tc "github.com/goplugin/plugin-starknet/integration-tests/testconfig"
"github.com/goplugin/plugin-starknet/ops/gauntlet"
"github.com/goplugin/plugin-starknet/ops/utils"
- "github.com/stretchr/testify/require"
)
var (
keepAlive bool
+ decimals = 9
)
func init() {
flag.BoolVar(&keepAlive, "keep-alive", false, "enable to keep the cluster alive")
}
-var (
- err error
- testState *common.Test
- decimals = 9
- mockServerVal = 900000000
-)
-
func TestOCRBasic(t *testing.T) {
- testState = &common.Test{
- T: t,
- }
- testState.Common = common.New()
- testState.Common.Default(t)
- // Setting this to the root of the repo for cmd exec func for Gauntlet
- testState.Sg, err = gauntlet.NewStarknetGauntlet(fmt.Sprintf("%s/", utils.ProjectRoot))
- require.NoError(t, err, "Could not get a new gauntlet struct")
+ for _, test := range []struct {
+ name string
+ env map[string]string
+ }{
+ {name: "embedded"},
+ {name: "plugins", env: map[string]string{
+ "CL_MEDIAN_CMD": "plugin-feeds",
+ "CL_SOLANA_CMD": "plugin-solana",
+ }},
+ } {
+ config, err := tc.GetConfig("Smoke", tc.OCR2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Setenv("PLUGIN_ENV_USER", *config.Common.User)
+ require.NoError(t, err, "Could not set PLUGIN_ENV_USER")
+ err = os.Setenv("INTERNAL_DOCKER_REPO", *config.Common.InternalDockerRepo)
+ require.NoError(t, err, "Could not set INTERNAL_DOCKER_REPO")
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ logging.Init()
+ //
+ state, err := common.NewOCRv2State(t, "smoke-ocr2", &config)
+ require.NoError(t, err, "Could not setup the ocrv2 state")
- testState.DeployCluster()
- require.NoError(t, err, "Deploying cluster should not fail")
- if testState.Common.Env.WillUseRemoteRunner() {
- return // short circuit here if using a remote runner
- }
- err = testState.Sg.SetupNetwork(testState.Common.L2RPCUrl)
- require.NoError(t, err, "Setting up gauntlet network should not fail")
- err = testState.DeployGauntlet(0, 100000000000, decimals, "auto", 1, 1)
- require.NoError(t, err, "Deploying contracts should not fail")
- if !testState.Common.Testnet {
- testState.Devnet.AutoLoadState(testState.OCR2Client, testState.OCRAddr)
- }
- testState.SetUpNodes(mockServerVal)
+ // K8s specific config and cleanup
+ if *config.Common.InsideK8s {
+ t.Cleanup(func() {
+ if err = actions.TeardownSuite(t, nil, state.Common.Env, state.PluginNodesK8s, nil, zapcore.PanicLevel, nil); err != nil {
+ state.TestConfig.L.Error().Err(err).Msg("Error tearing down environment")
+ }
+ })
+ }
+ if len(test.env) > 0 {
+ state.Common.TestEnvDetails.NodeOpts = append(state.Common.TestEnvDetails.NodeOpts, func(n *test_env.ClNode) {
+ if n.ContainerEnvs == nil {
+ n.ContainerEnvs = map[string]string{}
+ }
+ maps.Copy(n.ContainerEnvs, test.env)
+ })
+ }
+ state.DeployCluster()
+ state.Clients.GauntletClient, err = gauntlet.NewStarknetGauntlet(fmt.Sprintf("%s/", utils.ProjectRoot))
+ require.NoError(t, err, "Setting up gauntlet should not fail")
+ err = state.Clients.GauntletClient.SetupNetwork(state.Common.RPCDetails.RPCL2External, state.Account.Account, state.Account.PrivateKey)
+ require.NoError(t, err, "Setting up gauntlet network should not fail")
+ err = state.DeployGauntlet(0, 100000000000, decimals, "auto", 1, 1)
+ require.NoError(t, err, "Deploying contracts should not fail")
- err = testState.ValidateRounds(10, false)
- require.NoError(t, err, "Validating round should not fail")
-
- t.Cleanup(func() {
- err = actions.TeardownSuite(t, testState.Common.Env, utils.ProjectRoot, testState.Cc.PluginNodes, nil, zapcore.ErrorLevel)
- require.NoError(t, err, "Error tearing down environment")
- })
+ state.SetUpNodes()
+ err = state.ValidateRounds(*config.OCR2.NumberOfRounds, false)
+ require.NoError(t, err, "Validating round should not fail")
+ })
+ }
}
diff --git a/integration-tests/soak/ocr2_test.go b/integration-tests/soak/ocr2_test.go
index cb46ef5..ce323dc 100644
--- a/integration-tests/soak/ocr2_test.go
+++ b/integration-tests/soak/ocr2_test.go
@@ -1,58 +1,94 @@
-package soak_test
+package smoke_test
-// revive:disable:dot-imports
import (
"flag"
"fmt"
+ "maps"
+ "os"
"testing"
- "time"
+
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/goplugin/plugin-testing-framework/logging"
+ "github.com/goplugin/pluginv3.0/integration-tests/actions"
+ "github.com/goplugin/pluginv3.0/integration-tests/docker/test_env"
"github.com/goplugin/plugin-starknet/integration-tests/common"
+ tc "github.com/goplugin/plugin-starknet/integration-tests/testconfig"
"github.com/goplugin/plugin-starknet/ops/gauntlet"
"github.com/goplugin/plugin-starknet/ops/utils"
- "github.com/goplugin/pluginv3.0/integration-tests/actions"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap/zapcore"
)
var (
- keepAlive bool
- err error
- testState *common.Test
- decimals = 9
- mockServerVal = 900000000
+ keepAlive bool
+ decimals = 9
)
func init() {
flag.BoolVar(&keepAlive, "keep-alive", false, "enable to keep the cluster alive")
}
-func TestOCRSoak(t *testing.T) {
- testState = &common.Test{
- T: t,
- }
- testState.Common = common.New()
- testState.Common.Default(t)
- // Setting this to the root of the repo for cmd exec func for Gauntlet
- testState.Sg, err = gauntlet.NewStarknetGauntlet(fmt.Sprintf("%s/", utils.ProjectRoot))
- require.NoError(t, err, "Could not get a new gauntlet struct")
- testState.DeployCluster()
- require.NoError(t, err, "Deploying cluster should not fail")
- if testState.Common.Env.WillUseRemoteRunner() {
- return // short circuit here if using a remote runner
- }
- err = testState.Sg.SetupNetwork(testState.Common.L2RPCUrl)
- require.NoError(t, err, "Setting up network should not fail")
- time.Sleep(8 * time.Hour)
- err = testState.DeployGauntlet(0, 100000000000, decimals, "auto", 1, 1)
- require.NoError(t, err, "Deploying contracts should not fail")
- if !testState.Common.Testnet {
- testState.Devnet.AutoLoadState(testState.OCR2Client, testState.OCRAddr)
+
+func TestOCRBasicSoak(t *testing.T) {
+ for _, test := range []struct {
+ name string
+ env map[string]string
+ }{
+ {name: "embedded"},
+ {name: "plugins", env: map[string]string{
+ "CL_MEDIAN_CMD": "plugin-feeds",
+ "CL_SOLANA_CMD": "plugin-solana",
+ }},
+ } {
+ config, err := tc.GetConfig("Soak", tc.OCR2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Setenv("PLUGIN_ENV_USER", *config.Common.User)
+ require.NoError(t, err, "Could not set PLUGIN_ENV_USER")
+ err = os.Setenv("INTERNAL_DOCKER_REPO", *config.Common.InternalDockerRepo)
+ require.NoError(t, err, "Could not set INTERNAL_DOCKER_REPO")
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ logging.Init()
+ //
+ state, err := common.NewOCRv2State(t, "soak-ocr2", &config)
+ require.NoError(t, err, "Could not setup the ocrv2 state")
+
+ // K8s specific config and cleanup
+ if *config.Common.InsideK8s {
+ t.Cleanup(func() {
+ if err = actions.TeardownSuite(t, nil, state.Common.Env, state.PluginNodesK8s, nil, zapcore.PanicLevel, nil); err != nil {
+ state.TestConfig.L.Error().Err(err).Msg("Error tearing down environment")
+ }
+ })
+ }
+ if len(test.env) > 0 {
+ state.Common.TestEnvDetails.NodeOpts = append(state.Common.TestEnvDetails.NodeOpts, func(n *test_env.ClNode) {
+ if n.ContainerEnvs == nil {
+ n.ContainerEnvs = map[string]string{}
+ }
+ maps.Copy(n.ContainerEnvs, test.env)
+ })
+ }
+ state.DeployCluster()
+
+ if state.Common.Env.WillUseRemoteRunner() {
+ return
+ }
+
+ state.Clients.GauntletClient, err = gauntlet.NewStarknetGauntlet(fmt.Sprintf("%s/", utils.ProjectRoot))
+ require.NoError(t, err, "Setting up gauntlet should not fail")
+ err = state.Clients.GauntletClient.SetupNetwork(state.Common.RPCDetails.RPCL2External, state.Account.Account, state.Account.PrivateKey)
+ require.NoError(t, err, "Setting up gauntlet network should not fail")
+ err = state.DeployGauntlet(0, 100000000000, decimals, "auto", 1, 1)
+ require.NoError(t, err, "Deploying contracts should not fail")
+
+ state.SetUpNodes()
+
+ err = state.ValidateRounds(*config.OCR2.NumberOfRounds, true)
+ require.NoError(t, err, "Validating round should not fail")
+ })
}
- testState.SetUpNodes(mockServerVal)
- err = testState.ValidateRounds(99999999, true)
- require.NoError(t, err, "Validating round should not fail")
- t.Cleanup(func() {
- err = actions.TeardownSuite(t, testState.Common.Env, utils.ProjectRoot, testState.Cc.PluginNodes, nil, zapcore.ErrorLevel)
- require.NoError(t, err, "Error tearing down environment")
- })
}
diff --git a/integration-tests/test.Dockerfile b/integration-tests/test.Dockerfile
index d7f87f5..1c87a72 100644
--- a/integration-tests/test.Dockerfile
+++ b/integration-tests/test.Dockerfile
@@ -2,8 +2,10 @@ FROM nixos/nix:latest
ARG SUITES=smoke soak
ENV NIX_USER_CONF_FILES=/repo/nix.conf
+ENV PATH="/repo/cairo-build/bin:/repo/scarb-build/bin:${PATH}"
COPY . /repo/
WORKDIR /repo
+RUN nix develop -c helm repo update
RUN nix develop -c /repo/integration-tests/scripts/buildTests "${SUITES}"
ENTRYPOINT ["/repo/integration-tests/scripts/entrypoint"]
diff --git a/integration-tests/testconfig/configs_embed.go b/integration-tests/testconfig/configs_embed.go
new file mode 100644
index 0000000..e9decaa
--- /dev/null
+++ b/integration-tests/testconfig/configs_embed.go
@@ -0,0 +1,14 @@
+//go:build embed
+// +build embed
+
+package testconfig
+
+import "embed"
+
+//go:embed default.toml
+//go:embed ocr2/ocr2.toml
+var embeddedConfigsFs embed.FS
+
+func init() {
+ areConfigsEmbedded = true
+}
diff --git a/integration-tests/testconfig/configs_noembed.go b/integration-tests/testconfig/configs_noembed.go
new file mode 100644
index 0000000..95572c4
--- /dev/null
+++ b/integration-tests/testconfig/configs_noembed.go
@@ -0,0 +1,12 @@
+//go:build !embed
+// +build !embed
+
+package testconfig
+
+import "embed"
+
+var embeddedConfigsFs embed.FS
+
+func init() {
+ areConfigsEmbedded = false
+}
diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml
new file mode 100644
index 0000000..83c2523
--- /dev/null
+++ b/integration-tests/testconfig/default.toml
@@ -0,0 +1,38 @@
+# This is the default configuration so OCR2 tests can run without issues
+[PluginImage]
+image="public.ecr.aws/plugin/plugin"
+version="2.9.0"
+
+[Logging]
+test_log_collect=false
+
+[Logging.LogStream]
+log_targets=["file"]
+log_producer_timeout="10s"
+log_producer_retry_limit=10
+
+[Network]
+selected_networks=["SIMULATED"] # Not needed for Starknet but mandatory from CTF (do not change)
+
+[Network.RpcHttpUrls]
+simulated = ["http://127.0.0.1"] # Not needed for Starknet but mandatory from CTF (do not change)
+
+[Network.RpcWsUrls]
+simulated = ["wss://127.0.0.1"] # Not needed for Starknet but mandatory from CTF (do not change)
+
+[Common]
+internal_docker_repo = "public.ecr.aws/plugin"
+inside_k8 = false
+network = "localnet"
+user = "satoshi"
+stateful_db = false
+devnet_image = "shardlabs/starknet-devnet-rs:a147b4cd72f9ce9d1fa665d871231370db0f51c7"
+postgres_version = "15.7"
+
+[OCR2]
+node_count = 6
+test_duration = "30m"
+number_of_rounds = 10
+
+[OCR2.Smoke]
+enabled = true
diff --git a/integration-tests/testconfig/ocr2/ocr2.go b/integration-tests/testconfig/ocr2/ocr2.go
new file mode 100644
index 0000000..c16363b
--- /dev/null
+++ b/integration-tests/testconfig/ocr2/ocr2.go
@@ -0,0 +1,27 @@
+package ocr2
+
+import (
+ "errors"
+)
+
+type Config struct {
+ NumberOfRounds *int `toml:"number_of_rounds"`
+ NodeCount *int `toml:"node_count"`
+ TestDuration *string `toml:"test_duration"`
+}
+
+func (o *Config) Validate() error {
+ if o.NodeCount != nil && *o.NodeCount < 3 {
+ return errors.New("node_count must be set and cannot be less than 3")
+ }
+
+ if o.TestDuration == nil {
+ return errors.New("test_duration must be set")
+ }
+
+ if o.NumberOfRounds == nil {
+ return errors.New("number_of_rounds must be set")
+ }
+
+ return nil
+}
diff --git a/integration-tests/testconfig/ocr2/ocr2.toml b/integration-tests/testconfig/ocr2/ocr2.toml
new file mode 100644
index 0000000..9d1493a
--- /dev/null
+++ b/integration-tests/testconfig/ocr2/ocr2.toml
@@ -0,0 +1,3 @@
+[Common]
+node_count = 6
+test_duration = "30m"
\ No newline at end of file
diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go
new file mode 100644
index 0000000..e8997f4
--- /dev/null
+++ b/integration-tests/testconfig/testconfig.go
@@ -0,0 +1,428 @@
+package testconfig
+
+import (
+ "embed"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/barkimedes/go-deepcopy"
+ "github.com/google/uuid"
+ "github.com/pelletier/go-toml/v2"
+ "github.com/rs/zerolog"
+ "github.com/goplugin/seth"
+ "golang.org/x/text/cases"
+ "golang.org/x/text/language"
+
+ "github.com/goplugin/pluginv3.0/integration-tests/types/config/node"
+
+ common_cfg "github.com/goplugin/plugin-common/pkg/config"
+
+ ctf_config "github.com/goplugin/plugin-testing-framework/config"
+ k8s_config "github.com/goplugin/plugin-testing-framework/k8s/config"
+ "github.com/goplugin/plugin-testing-framework/logging"
+ "github.com/goplugin/plugin-testing-framework/utils/osutil"
+ "github.com/goplugin/plugin-testing-framework/utils/ptr"
+
+ ocr2_config "github.com/goplugin/plugin-starknet/integration-tests/testconfig/ocr2"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/config"
+)
+
+type TestConfig struct {
+ PluginImage *ctf_config.PluginImageConfig `toml:"PluginImage"`
+ Logging *ctf_config.LoggingConfig `toml:"Logging"`
+ PluginUpgradeImage *ctf_config.PluginImageConfig `toml:"PluginUpgradeImage"`
+ Network *ctf_config.NetworkConfig `toml:"Network"`
+ Common *Common `toml:"Common"`
+ OCR2 *ocr2_config.Config `toml:"OCR2"`
+ ConfigurationName string `toml:"-"`
+
+ // getter funcs for passing parameters
+ GetChainID, GetFeederURL, GetRPCL2Internal, GetRPCL2InternalAPIKey func() string
+}
+
+func (c *TestConfig) GetLoggingConfig() *ctf_config.LoggingConfig {
+ return c.Logging
+}
+
+func (c *TestConfig) GetPrivateEthereumNetworkConfig() *ctf_config.EthereumNetworkConfig {
+ return &ctf_config.EthereumNetworkConfig{}
+}
+
+func (c *TestConfig) GetSethConfig() *seth.Config {
+ return nil
+}
+
+func (c *TestConfig) GetPyroscopeConfig() *ctf_config.PyroscopeConfig {
+ return &ctf_config.PyroscopeConfig{}
+}
+
+var embeddedConfigs embed.FS
+var areConfigsEmbedded bool
+
+func init() {
+ embeddedConfigs = embeddedConfigsFs
+}
+
+// Saves Test Config to a local file
+func (c *TestConfig) Save() (string, error) {
+ filePath := fmt.Sprintf("test_config-%s.toml", uuid.New())
+
+ content, err := toml.Marshal(*c)
+ if err != nil {
+ return "", fmt.Errorf("error marshaling test config: %w", err)
+ }
+
+ err = os.WriteFile(filePath, content, 0600)
+ if err != nil {
+ return "", fmt.Errorf("error writing test config: %w", err)
+ }
+
+ return filePath, nil
+}
+
+// MustCopy Returns a deep copy of the Test Config or panics on error
+func (c TestConfig) MustCopy() any {
+ return deepcopy.MustAnything(c).(TestConfig)
+}
+
+// MustCopy Returns a deep copy of struct passed to it and returns a typed copy (or panics on error)
+func MustCopy[T any](c T) T {
+ return deepcopy.MustAnything(c).(T)
+}
+
+func (c TestConfig) GetNetworkConfig() *ctf_config.NetworkConfig {
+ return c.Network
+}
+
+func (c TestConfig) GetPluginImageConfig() *ctf_config.PluginImageConfig {
+ return c.PluginImage
+}
+
+func (c TestConfig) GetCommonConfig() *Common {
+ return c.Common
+}
+
+func (c *TestConfig) GetNodeConfig() *ctf_config.NodeConfig {
+ cfgTOML, err := c.GetNodeConfigTOML()
+ if err != nil {
+ log.Fatalf("failed to parse TOML config: %s", err)
+ return nil
+ }
+
+ return &ctf_config.NodeConfig{
+ BaseConfigTOML: cfgTOML,
+ }
+}
+
+func (c TestConfig) GetNodeConfigTOML() (string, error) {
+ var chainID, feederURL, RPCL2Internal, RPCL2InternalAPIKey string
+ if c.GetChainID != nil {
+ chainID = c.GetChainID()
+ }
+ if c.GetFeederURL != nil {
+ feederURL = c.GetFeederURL()
+ }
+ if c.GetRPCL2Internal != nil {
+ RPCL2Internal = c.GetRPCL2Internal()
+ }
+ if c.GetRPCL2InternalAPIKey != nil {
+ RPCL2InternalAPIKey = c.GetRPCL2InternalAPIKey()
+ }
+
+ starkConfig := config.TOMLConfig{
+ Enabled: ptr.Ptr(true),
+ ChainID: ptr.Ptr(chainID),
+ FeederURL: common_cfg.MustParseURL(feederURL),
+ Nodes: []*config.Node{
+ {
+ Name: ptr.Ptr("primary"),
+ URL: common_cfg.MustParseURL(RPCL2Internal),
+ APIKey: ptr.Ptr(RPCL2InternalAPIKey),
+ },
+ },
+ }
+ baseConfig := node.NewBaseConfig()
+ baseConfig.Starknet = config.TOMLConfigs{
+ &starkConfig,
+ }
+ baseConfig.OCR2.Enabled = ptr.Ptr(true)
+ baseConfig.P2P.V2.Enabled = ptr.Ptr(true)
+ fiveSecondDuration := common_cfg.MustNewDuration(5 * time.Second)
+
+ baseConfig.P2P.V2.DeltaDial = fiveSecondDuration
+ baseConfig.P2P.V2.DeltaReconcile = fiveSecondDuration
+ baseConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"}
+
+ return baseConfig.TOMLString()
+}
+
+func (c TestConfig) GetPluginUpgradeImageConfig() *ctf_config.PluginImageConfig {
+ return c.PluginUpgradeImage
+}
+
+func (c TestConfig) GetConfigurationName() string {
+ return c.ConfigurationName
+}
+
+func (c *TestConfig) AsBase64() (string, error) {
+ content, err := toml.Marshal(*c)
+ if err != nil {
+ return "", fmt.Errorf("error marshaling test config: %w", err)
+ }
+
+ return base64.StdEncoding.EncodeToString(content), nil
+}
+
+type Common struct {
+ Network *string `toml:"network"`
+ InsideK8s *bool `toml:"inside_k8"`
+ User *string `toml:"user"`
+ // if rpc requires api key to be passed as an HTTP header
+ L2RPCApiKey *string `toml:"l2_rpc_url_api_key"`
+ L2RPCUrl *string `toml:"l2_rpc_url"`
+ PrivateKey *string `toml:"private_key"`
+ Account *string `toml:"account"`
+ Stateful *bool `toml:"stateful_db"`
+ InternalDockerRepo *string `toml:"internal_docker_repo"`
+ DevnetImage *string `toml:"devnet_image"`
+ PostgresVersion *string `toml:"postgres_version"`
+}
+
+func (c *Common) Validate() error {
+ if c.Network == nil {
+ return fmt.Errorf("network must be set")
+ }
+
+ switch *c.Network {
+ case "localnet":
+ if c.DevnetImage == nil {
+ return fmt.Errorf("devnet_image must be set")
+ }
+ case "testnet":
+ if c.PrivateKey == nil {
+ return fmt.Errorf("private_key must be set")
+ }
+ if c.L2RPCUrl == nil {
+ return fmt.Errorf("l2_rpc_url must be set")
+ }
+
+ if c.Account == nil {
+ return fmt.Errorf("account must be set")
+ }
+ default:
+ return fmt.Errorf("network must be either 'localnet' or 'testnet'")
+ }
+
+ if c.InsideK8s == nil {
+ return fmt.Errorf("inside_k8 must be set")
+ }
+
+ if c.InternalDockerRepo == nil {
+ return fmt.Errorf("internal_docker_repo must be set")
+ }
+
+ if c.User == nil {
+ return fmt.Errorf("user must be set")
+ }
+
+ if c.Stateful == nil {
+ return fmt.Errorf("stateful_db state for db must be set")
+ }
+
+ if c.PostgresVersion == nil {
+ return fmt.Errorf("postgres_version must be set")
+ }
+
+ return nil
+}
+
+type Product string
+
+const (
+ OCR2 Product = "ocr2"
+)
+
+const TestTypeEnvVarName = "TEST_TYPE"
+
+const (
+ Base64OverrideEnvVarName = k8s_config.EnvBase64ConfigOverride
+ NoKey = "NO_KEY"
+)
+
+func GetConfig(configurationName string, product Product) (TestConfig, error) {
+ logger := logging.GetTestLogger(nil)
+
+ configurationName = strings.ReplaceAll(configurationName, "/", "_")
+ configurationName = strings.ReplaceAll(configurationName, " ", "_")
+ configurationName = cases.Title(language.English, cases.NoLower).String(configurationName)
+ fileNames := []string{
+ "default.toml",
+ fmt.Sprintf("%s.toml", product),
+ "overrides.toml",
+ }
+
+ testConfig := TestConfig{}
+ testConfig.ConfigurationName = configurationName
+ logger.Debug().Msgf("Will apply configuration named '%s' if it is found in any of the configs", configurationName)
+
+ var handleSpecialOverrides = func(logger zerolog.Logger, filename, configurationName string, target *TestConfig, content []byte, product Product) error {
+ switch product {
+ default:
+ err := ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, target, content)
+ if err != nil {
+ return fmt.Errorf("error reading file %s: %w", filename, err)
+ }
+
+ return nil
+ }
+ }
+
+ // read embedded configs is build tag "embed" is set
+ // this makes our life much easier when using a binary
+ if areConfigsEmbedded {
+ logger.Info().Msg("Reading embedded configs")
+ embeddedFiles := []string{"default.toml", fmt.Sprintf("%s/%s.toml", product, product)}
+ for _, fileName := range embeddedFiles {
+ file, err := embeddedConfigs.ReadFile(fileName)
+ if err != nil && errors.Is(err, os.ErrNotExist) {
+ logger.Debug().Msgf("Embedded config file %s not found. Continuing", fileName)
+ continue
+ } else if err != nil {
+ return TestConfig{}, fmt.Errorf("error reading embedded config: %w", err)
+ }
+
+ err = handleSpecialOverrides(logger, fileName, "", &testConfig, file, product) // use empty configurationName to read default config
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error unmarshalling embedded config: %w", err)
+ }
+ }
+ }
+
+ logger.Info().Msg("Reading configs from file system")
+ for _, fileName := range fileNames {
+ logger.Debug().Msgf("Looking for config file %s", fileName)
+ filePath, err := osutil.FindFile(fileName, osutil.DEFAULT_STOP_FILE_NAME, 3)
+
+ if err != nil && errors.Is(err, os.ErrNotExist) {
+ logger.Debug().Msgf("Config file %s not found", fileName)
+ continue
+ } else if err != nil {
+ return TestConfig{}, fmt.Errorf("error looking for file %s: %w", filePath, err)
+ }
+ logger.Debug().Str("location", filePath).Msgf("Found config file %s", fileName)
+
+ content, err := readFile(filePath)
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error reading file %s: %w", filePath, err)
+ }
+
+ err = handleSpecialOverrides(logger, fileName, "", &testConfig, content, product) // use empty configurationName to read default config
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error reading file %s: %w", filePath, err)
+ }
+ }
+
+ logger.Info().Msg("Reading configs from Base64 override env var")
+ configEncoded, isSet := os.LookupEnv(Base64OverrideEnvVarName)
+ if isSet && configEncoded != "" {
+ logger.Debug().Msgf("Found base64 config override environment variable '%s' found", Base64OverrideEnvVarName)
+ decoded, err := base64.StdEncoding.DecodeString(configEncoded)
+ if err != nil {
+ return TestConfig{}, err
+ }
+
+ err = handleSpecialOverrides(logger, Base64OverrideEnvVarName, "", &testConfig, decoded, product) // use empty configurationName to read default config
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error unmarshaling base64 config: %w", err)
+ }
+ } else {
+ logger.Debug().Msg("Base64 config override from environment variable not found")
+ }
+
+ // it neede some custom logic, so we do it separately
+ err := testConfig.readNetworkConfiguration()
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error reading network config: %w", err)
+ }
+
+ logger.Debug().Msg("Validating test config")
+ err = testConfig.Validate()
+ if err != nil {
+ return TestConfig{}, fmt.Errorf("error validating test config: %w", err)
+ }
+
+ if testConfig.Common == nil {
+ testConfig.Common = &Common{}
+ }
+
+ logger.Debug().Msg("Correct test config constructed successfully")
+ return testConfig, nil
+}
+
+func (c *TestConfig) readNetworkConfiguration() error {
+ // currently we need to read that kind of secrets only for network configuration
+ if c == nil {
+ c.Network = &ctf_config.NetworkConfig{}
+ }
+
+ c.Network.UpperCaseNetworkNames()
+ err := c.Network.Default()
+ if err != nil {
+ return fmt.Errorf("error reading default network config: %w", err)
+ }
+
+ return nil
+}
+
+func (c *TestConfig) Validate() error {
+ defer func() {
+ if r := recover(); r != nil {
+ panic(fmt.Errorf("Panic during test config validation: '%v'. Most probably due to presence of partial product config", r))
+ }
+ }()
+ if c.PluginImage == nil {
+ return fmt.Errorf("plugin image config must be set")
+ }
+ if err := c.PluginImage.Validate(); err != nil {
+ return fmt.Errorf("plugin image config validation failed: %w", err)
+ }
+ if c.PluginUpgradeImage != nil {
+ if err := c.PluginUpgradeImage.Validate(); err != nil {
+ return fmt.Errorf("plugin upgrade image config validation failed: %w", err)
+ }
+ }
+ if err := c.Network.Validate(); err != nil {
+ return fmt.Errorf("network config validation failed: %w", err)
+ }
+
+ if c.Common == nil {
+ return fmt.Errorf("common config must be set")
+ }
+
+ if err := c.Common.Validate(); err != nil {
+ return fmt.Errorf("Common config validation failed: %w", err)
+ }
+
+ if c.OCR2 == nil {
+ return fmt.Errorf("OCR2 config must be set")
+ }
+
+ if err := c.OCR2.Validate(); err != nil {
+ return fmt.Errorf("OCR2 config validation failed: %w", err)
+ }
+ return nil
+}
+
+func readFile(filePath string) ([]byte, error) {
+ content, err := os.ReadFile(filePath)
+ if err != nil {
+ return nil, fmt.Errorf("error reading file %s: %w", filePath, err)
+ }
+
+ return content, nil
+}
diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go
index f7d19c5..99739fe 100644
--- a/integration-tests/utils/common.go
+++ b/integration-tests/utils/common.go
@@ -7,7 +7,7 @@ import (
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
- envConf "github.com/goplugin/plugin-env/config"
+ envConf "github.com/goplugin/plugin-testing-framework/k8s/config"
)
// GetTestLogger TODO: This is a duplicate of the same function in plugin-testing-framework. We should replace this with a call to the ctf version when plugin-starknet is updated to use the latest ctf version.
@@ -19,6 +19,8 @@ func GetTestLogger(t *testing.T) zerolog.Logger {
}
lvl, err := zerolog.ParseLevel(lvlStr)
require.NoError(t, err, "error parsing log level")
- l := zerolog.New(zerolog.NewTestWriter(t)).Output(zerolog.ConsoleWriter{Out: os.Stderr}).Level(lvl).With().Timestamp().Logger()
+ l := zerolog.New(zerolog.NewTestWriter(t)).
+ Output(zerolog.ConsoleWriter{Out: os.Stderr, NoColor: true}).
+ Level(lvl).With().Timestamp().Logger()
return l
}
diff --git a/jest.config.ts b/jest.config.ts
index 9529342..c788af5 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -32,6 +32,7 @@ const config: Config.InitialOptions = {
projectConfig('starknet-gauntlet-oz'),
projectConfig('starknet-gauntlet-token'),
projectConfig('starknet-gauntlet-emergency-protocol'),
+ projectConfig('starknet-gauntlet-ledger'),
],
}
export default config
diff --git a/monitoring/README.md b/monitoring/README.md
index a8075b4..3ef4a0a 100644
--- a/monitoring/README.md
+++ b/monitoring/README.md
@@ -3,17 +3,12 @@
## Useful links
- Starknet on-chain monitor [generated docs](https://pkg.go.dev/github.com/goplugin/plugin-starknet/monitoring/pkg/monitoring).
-- On-chain monitoring (OM) framework architecture docs in [blueprints](https://github.com/goplugin/plugin-blueprints/blob/master/monitoring/README.md).
-- OM framework [generated docs](https://pkg.go.dev/github.com/goplugin/plugin-relay/pkg/monitoring).
+- On-chain monitoring (OM) framework architecture docs in [blueprints](https://github.com/goplugin/pluginv3.0-blueprints/blob/master/monitoring/README.md).
+- OM framework [generated docs](https://pkg.go.dev/github.com/goplugin/plugin-common/pkg/monitoring).
## Local development
-- Start the monitor's third party dependencies using [docker-compose](https://docs.docker.com/compose/).
- Use the docker-compose.yml file in `./ops`:
-
-```sh
-docker-compose up
-```
+Note: Previously, this monitor also wrote to Kafka, but the dependency on Kafka has been removed in order to simplify deployment. The kafka topics were unused anyway.
- Start an http server that mimics weiwatchers locally. It needs to export a json configuration file for feeds:
@@ -60,17 +55,6 @@ STARKNET_CHAIN_ID="1" \
STARKNET_READ_TIMEOUT="5s" \
STARKNET_POLL_INTERVAL="10s" #test \
STARKNET_PLI_TOKEN_ADDRESS="" \
-KAFKA_BROKERS="localhost:29092" \
-KAFKA_CLIENT_ID="starknet" \
-KAFKA_SECURITY_PROTOCOL="PLAINTEXT" \
-KAFKA_SASL_MECHANISM="PLAIN" \
-KAFKA_SASL_USERNAME="" \
-KAFKA_SASL_PASSWORD="" \
-KAFKA_CONFIG_SET_SIMPLIFIED_TOPIC="config_set_simplified" \
-KAFKA_TRANSMISSION_TOPIC="transmission_topic" \
-SCHEMA_REGISTRY_URL="http://localhost:8989" \
-SCHEMA_REGISTRY_USERNAME="" \
-SCHEMA_REGISTRY_PASSWORD="" \
HTTP_ADDRESS="localhost:3000" \
FEEDS_URL="http://localhost:4000/feeds.json" \
NODES_URL="http://localhost:4000/nodes.json" \
@@ -82,10 +66,3 @@ go run ./cmd/monitoring/main.go
```bash
curl http://localhost:3000/metrics
```
-
-- To check the output for Kafka, you need to install [kcat](https://github.com/edenhill/kcat). After you install, run:
-
-```bash
-kcat -b localhost:29092 -t config_set_simplified
-kcat -b localhost:29092 -t transmission_topic
-```
diff --git a/monitoring/cmd/monitoring/main.go b/monitoring/cmd/monitoring/main.go
index 7a75db0..84521f6 100644
--- a/monitoring/cmd/monitoring/main.go
+++ b/monitoring/cmd/monitoring/main.go
@@ -1,12 +1,11 @@
package main
import (
- "context"
"fmt"
- "github.com/goplugin/plugin-relay/pkg/logger"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ "github.com/goplugin/plugin-common/pkg/logger"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/erc20"
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
"github.com/goplugin/plugin-starknet/relayer/pkg/starknet"
@@ -14,8 +13,6 @@ import (
)
func main() {
- ctx := context.Background()
-
log, err := logger.New()
if err != nil {
log.Fatal(err)
@@ -36,6 +33,7 @@ func main() {
starknetClient, err := starknet.NewClient(
starknetConfig.GetChainID(),
starknetConfig.GetRPCEndpoint(),
+ starknetConfig.GetRPCApiKey(),
logger.With(log, "component", "starknet-client"),
&readTimeout,
)
@@ -50,11 +48,21 @@ func main() {
log.Fatalw("failed to build a ocr2.Client", "error", err)
}
+ strTokenClient, err := erc20.NewClient(
+ starknetClient,
+ logger.With(log, "component", "erc20-client"),
+ starknetConfig.GetStrkTokenAddress(),
+ )
+
+ if err != nil {
+ log.Fatalw("failed to build erc20-client", "error", err)
+ }
+
envelopeSourceFactory := monitoring.NewEnvelopeSourceFactory(ocr2Client)
txResultsFactory := monitoring.NewTxResultsSourceFactory(ocr2Client)
- monitor, err := relayMonitoring.NewMonitor(
- ctx,
+ monitor, err := monitoring.NewMonitorPrometheusOnly(
+ make(chan struct{}),
logger.With(log, "component", "monitor"),
starknetConfig,
envelopeSourceFactory,
@@ -67,13 +75,26 @@ func main() {
return
}
+ // per-feed factories
proxySourceFactory := monitoring.NewProxySourceFactory(ocr2Client)
- monitor.SourceFactories = append(monitor.SourceFactories, proxySourceFactory)
+ transmissionsDetailsSourceFactory := monitoring.NewTransmissionDetailsSourceFactory(ocr2Client)
+ monitor.SourceFactories = append(monitor.SourceFactories, proxySourceFactory, transmissionsDetailsSourceFactory)
+
+ metricsBuilder := monitoring.NewMetrics(logger.With(log, "component", "starknet-metrics-builder"))
+
+ prometheusExporterFactory := monitoring.NewPrometheusExporterFactory(metricsBuilder)
+ transmissionsDetailsExporterFactory := monitoring.NewTransmissionDetailsExporterFactory(metricsBuilder)
+ monitor.ExporterFactories = append(monitor.ExporterFactories, prometheusExporterFactory, transmissionsDetailsExporterFactory)
+
+ // network factories
+ nodeBalancesSourceFactory := monitoring.NewNodeBalancesSourceFactory(strTokenClient)
+ monitor.NetworkSourceFactories = append(monitor.NetworkSourceFactories, nodeBalancesSourceFactory)
- prometheusExporterFactory := monitoring.NewPrometheusExporterFactory(
- monitoring.NewMetrics(logger.With(log, "component", "starknet-metrics")),
+ nodeBalancesExporterFactory := monitoring.NewNodeBalancesExporterFactory(
+ logger.With(log, "node-balances-exporter"),
+ metricsBuilder,
)
- monitor.ExporterFactories = append(monitor.ExporterFactories, prometheusExporterFactory)
+ monitor.NetworkExporterFactories = append(monitor.NetworkExporterFactories, nodeBalancesExporterFactory)
monitor.Run()
log.Info("monitor stopped")
diff --git a/monitoring/go.mod b/monitoring/go.mod
index 8a8796c..9c5114f 100644
--- a/monitoring/go.mod
+++ b/monitoring/go.mod
@@ -1,71 +1,148 @@
module github.com/goplugin/plugin-starknet/monitoring
-go 1.20
+go 1.22
+
+toolchain go1.22.1
require (
- github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac
- github.com/dontpanicdao/caigo v0.4.0
- github.com/prometheus/client_golang v1.14.0
- github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82
- github.com/goplugin/plugin-starknet/relayer v0.0.0-20230412143414-b1e534d34592
- github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc
- github.com/stretchr/testify v1.8.2
- go.uber.org/multierr v1.9.0
+ github.com/NethermindEth/juno v0.3.1
+ github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb
+ github.com/prometheus/client_golang v1.17.0
+ github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b
+ github.com/goplugin/plugin-starknet/relayer v0.0.0-20230508053614-9f2fd5fd4ff1
+ github.com/goplugin/plugin-libocr v0.0.0-20240419185742-fd3cab206b2c
+ //github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b
+ //github.com/goplugin/plugin-starknet/relayer v0.0.0-20230508053614-9f2fd5fd4ff1
+ //github.com/goplugin/plugin-libocr v0.0.0-20240419185742-fd3cab206b2c
+ github.com/stretchr/testify v1.9.0
+ go.uber.org/multierr v1.11.0
)
require (
- github.com/benbjohnson/clock v1.3.0 // indirect
+ github.com/DataDog/zstd v1.5.2 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/confluentinc/confluent-kafka-go v1.9.2 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/deckarep/golang-set/v2 v2.1.0 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
- github.com/ethereum/go-ethereum v1.11.5 // indirect
+ github.com/bits-and-blooms/bitset v1.10.0 // indirect
+ github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
+ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 // indirect
+ github.com/buger/jsonparser v1.1.1 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/cockroachdb/errors v1.9.1 // indirect
+ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
+ github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect
+ github.com/cockroachdb/redact v1.1.3 // indirect
+ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
+ github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 // indirect
+ github.com/consensys/bavard v0.1.13 // indirect
+ github.com/consensys/gnark-crypto v0.12.1 // indirect
+ github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/deckarep/golang-set/v2 v2.3.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
+ github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
+ github.com/ethereum/go-ethereum v1.13.8 // indirect
+ github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.5.0 // indirect
+ github.com/getsentry/sentry-go v0.19.0 // indirect
+ github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/go-stack/stack v1.8.1 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/google/go-querystring v1.1.0 // indirect
- github.com/google/uuid v1.3.0 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
- github.com/holiman/uint256 v1.2.0 // indirect
+ github.com/go-playground/locales v0.14.0 // indirect
+ github.com/go-playground/universal-translator v0.18.0 // indirect
+ github.com/go-playground/validator/v10 v10.11.1 // indirect
+ github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
+ github.com/gogo/protobuf v1.3.3 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.1 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
+ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
+ github.com/hashicorp/go-hclog v1.5.0 // indirect
+ github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99 // indirect
+ github.com/hashicorp/yamux v0.1.1 // indirect
+ github.com/holiman/uint256 v1.2.4 // indirect
+ github.com/invopop/jsonschema v0.12.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
+ github.com/klauspost/compress v1.17.2 // indirect
+ github.com/kr/pretty v0.3.1 // indirect
+ github.com/kr/text v0.2.0 // indirect
+ github.com/leodido/go-urn v1.2.1 // indirect
github.com/linkedin/goavro/v2 v2.12.0 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
+ github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
+ github.com/oklog/run v1.1.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.39.0 // indirect
- github.com/prometheus/procfs v0.9.0 // indirect
+ github.com/prometheus/client_model v0.5.0 // indirect
+ github.com/prometheus/common v0.45.0 // indirect
+ github.com/prometheus/procfs v0.12.0 // indirect
github.com/riferrei/srclient v0.5.4 // indirect
- github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 // indirect
- github.com/satori/go.uuid v1.2.0 // indirect
+ github.com/rogpeppe/go-internal v1.12.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/tklauser/go-sysconf v0.3.10 // indirect
- github.com/tklauser/numcpus v0.5.0 // indirect
- github.com/yusufpapurcu/wmi v1.2.2 // indirect
- go.uber.org/atomic v1.10.0 // indirect
- go.uber.org/zap v1.24.0 // indirect
- golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
- golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.7.0 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
- gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
+ github.com/goplugin/grpc-proxy v0.1.1 // plugin update changes
+ //github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/supranational/blst v0.3.11 // indirect
+ github.com/test-go/testify v1.1.4 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
+ github.com/x448/float16 v0.8.4 // indirect
+ github.com/yusufpapurcu/wmi v1.2.3 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect
+ go.opentelemetry.io/otel v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0 // indirect
+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
+ go.opentelemetry.io/otel/log v0.4.0 // indirect
+ go.opentelemetry.io/otel/metric v1.28.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.28.0 // indirect
+ go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect
+ go.opentelemetry.io/otel/sdk/metric v1.28.0 // indirect
+ go.opentelemetry.io/otel/trace v1.28.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.3.1 // indirect
+ go.uber.org/zap v1.27.0 // indirect
+ golang.org/x/crypto v0.26.0 // indirect
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.28.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.24.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
+ google.golang.org/grpc v1.65.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ rsc.io/tmplfunc v0.0.3 // indirect
)
replace (
- // Fix go mod tidy issue for ambiguous imports from go-ethereum
- // See https://github.com/ugorji/go/issues/279
- github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1
-
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
+ // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69
+ github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.1.1 //plugin update changes
+ //github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.0.0-20230731113816-f1be6620749f
+
github.com/goplugin/plugin-starknet/relayer => ../relayer
)
diff --git a/monitoring/go.sum b/monitoring/go.sum
index 3e0b0b4..0352f76 100644
--- a/monitoring/go.sum
+++ b/monitoring/go.sum
@@ -1,81 +1,179 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
+github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac h1:TQ2m26VW06Df1P82Ed/jZhBtf13pReWyl2XQ8hy+J08=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac/go.mod h1:FTk2+xybtQe5X+oNFx+a0n5EeZMD9Nc+LCH4fxFwrEE=
-github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
-github.com/actgardner/gogen-avro/v10 v10.1.0/go.mod h1:o+ybmVjEa27AAr35FRqU98DJu1fXES56uXniYFv4yDA=
-github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ=
-github.com/actgardner/gogen-avro/v9 v9.1.0/go.mod h1:nyTj6wPqDJoxM3qdnjcLv+EnMDSDFqE0qDpva2QRmKc=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
-github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
+github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
+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/hcsshim v0.9.4 h1:mnUj0ivWy6UzbB1uLFqKR6F+ZyiDc7j4iGgHTpO+5+I=
+github.com/Microsoft/hcsshim v0.9.4/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
+github.com/NethermindEth/juno v0.3.1 h1:AW72LiAm9gqUeCVJWvepnZcTnpU4Vkl0KzPMxS+42FA=
+github.com/NethermindEth/juno v0.3.1/go.mod h1:SGbTpgGaCsxhFsKOid7Ylnz//WZ8swtILk+NbHGsk/Q=
+github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb h1:Mv8SscePPyw2ju4igIJAjFgcq5zCQfjgbz53DwYu5mc=
+github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb/go.mod h1:gQkhWpAs9/QR6reZU2xoi1UIYlMS64FLTlh9CrgHH/Y=
+github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
+github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
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/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
-github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E=
-github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
+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/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
+github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU=
+github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
+github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
+github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cespare/cp v1.1.1/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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
+github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
+github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk=
+github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
-github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk=
+github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
+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.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
-github.com/confluentinc/confluent-kafka-go v1.9.2 h1:gV/GxhMBUb03tFWkN+7kdhg+zf+QUM+wVkI9zwh770Q=
-github.com/confluentinc/confluent-kafka-go v1.9.2/go.mod h1:ptXNqsuDfYbAE/LBW6pnwWZElUoWxHoV8E43DCrliyo=
+github.com/cockroachdb/redact v1.1.3/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/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
+github.com/confluentinc/confluent-kafka-go/v2 v2.3.0 h1:icCHutJouWlQREayFwCc7lxDAhws08td+W3/gdqgZts=
+github.com/confluentinc/confluent-kafka-go/v2 v2.3.0/go.mod h1:/VTy8iEpe6mD9pkCH5BhijlUl8ulUXymKv1Qig5Rgb8=
+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/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
+github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
+github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
+github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/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/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
-github.com/dontpanicdao/caigo v0.4.0 h1:S0wRKh2EZ9qj6IfHZIGXxiJF37emRCqnZwDhRb1+DJ4=
-github.com/dontpanicdao/caigo v0.4.0/go.mod h1:1YuwgcVLODaS/n0vfuYN/Q0mdWs8UDfDMkSpUdkKXD4=
-github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
+github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+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=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
+github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
+github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
+github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ=
-github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
-github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
-github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
-github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
-github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
+github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
+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.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg=
+github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA=
+github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
+github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
+github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
-github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+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/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
+github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM=
+github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE=
+github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
+github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
+github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
+github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg=
+github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
-github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
+github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
+github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
+github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
+github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
+github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
+github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
+github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
+github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
+github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
+github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
+github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
@@ -86,234 +184,490 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-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/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-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/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
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/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
-github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+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.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hamba/avro v1.5.6/go.mod h1:3vNT0RLXXpFm2Tb/5KC71ZRJlOroggq1Rcitb6k4Fr8=
-github.com/heetch/avro v0.3.1/go.mod h1:4xn38Oz/+hiEUTpbVfGVLfvOg0yKLlRP7Q9+gJJILgA=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
+github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
+github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
+github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8=
+github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A=
+github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
+github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99 h1:OSQYEsRT3tRttZkk6zyC3aAaliwd7Loi/KgXgXxGtwA=
+github.com/hashicorp/go-plugin v1.6.2-0.20240829161738-06afb6d7ae99/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
-github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
-github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
-github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
-github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
-github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
-github.com/invopop/jsonschema v0.4.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
+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/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/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
+github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
+github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
+github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
+github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
+github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
+github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
-github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
-github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
-github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
-github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
-github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
+github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
+github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
+github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
+github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
+github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
+github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
+github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
+github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/linkedin/goavro v2.1.0+incompatible/go.mod h1:bBCwI2eGYpUI/4820s67MElg9tdeLbINjLjiM2xZFYM=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
+github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU=
+github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
+github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
+github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
-github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
-github.com/linkedin/goavro/v2 v2.10.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
-github.com/linkedin/goavro/v2 v2.11.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
github.com/linkedin/goavro/v2 v2.12.0 h1:rIQQSj8jdAUlKQh6DttK8wCRv4t4QO09g1C4aBWXslg=
github.com/linkedin/goavro/v2 v2.12.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk=
-github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
+github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+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/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
+github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0=
+github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
+github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
-github.com/nrwiersma/avro-benchmarks v0.0.0-20210913175520-21aec48c8f76/go.mod h1:iKyFMidsk/sVYONJRE372sJuX/QTRPacU7imPqqsu7g=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=
+github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
+github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
+github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
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.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
+github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
+github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
+github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
-github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
+github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
+github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
-github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
-github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4=
+github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI=
github.com/riferrei/srclient v0.5.4 h1:dfwyR5u23QF7beuVl2WemUY2KXh5+Sc4DHKyPXBNYuc=
github.com/riferrei/srclient v0.5.4/go.mod h1:vbkLmWcgYa7JgfPvuy/+K8fTS0p1bApqadxrxi/S1MI=
-github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
-github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 h1:lEOLY2vyGIqKWUI9nzsOJRV3mb3WC9dXYORsLEUcoeY=
-github.com/santhosh-tekuri/jsonschema/v5 v5.1.1/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 h1:WCcC4vZDS1tYNxjWlwRJZQy28r8CMoggKnxNzxsVDMQ=
+github.com/santhosh-tekuri/jsonschema/v5 v5.2.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
+github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82 h1:FX7LW/czuotFwzfK3UavL7HkKQv6fn/5wzcZASdKWQ0=
-github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82/go.mod h1:3E3PXaMEl2gADk/DTkbOxsvtpDcJ5ZSyW+vt0TjsEH0=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc h1:aSCDAai0Dmbhp/KHTtJnC/EJcaEz4CAO80SKRzRZiQA=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc/go.mod h1:5JnCHuYgmIP9ZyXzgAfI5Iwu0WxBtBKp+ApeT5o1Cjw=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b h1:eW1CSdNcDtOFqjrtfR93KTg80rHP+WWh5UybdJcdU8M=
+github.com/goplugin/plugin-common v0.2.2-0.20240911152814-4836d1d7f16b/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc=
+github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs=
+github.com/goplugin/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA=
+github.com/goplugin/plugin-libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI=
+github.com/goplugin/plugin-libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+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/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
-github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
-github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
-github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
-github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
-github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+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/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
+github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
+github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
+github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
+github.com/testcontainers/testcontainers-go v0.14.0 h1:h0D5GaYG9mhOWr2qHdEKDXpkce/VlvaYOCzTRi6UBi8=
+github.com/testcontainers/testcontainers-go v0.14.0/go.mod h1:hSRGJ1G8Q5Bw2gXgPulJOLlEBaYJHeBSOkQM5JLG+JQ=
+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/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
+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=
+github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
-github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
-go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
-go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
-go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
-go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
+github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0=
+go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
+go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9 h1:UiRNKd1OgqsLbFwE+wkAWTdiAxXtCBqKIHeBIse4FUA=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240823153156-2a54df7bffb9/go.mod h1:eqZlW3pJWhjyexnDPrdQxix1pn0wwhI4AO4GKpP/bMI=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 h1:U2guen0GhqH8o/G2un8f/aG/y++OuW6MyCo6hT9prXk=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0/go.mod h1:yeGZANgEcpdx/WK0IvvRFC+2oLiMS2u4L/0Rj2M2Qr0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0 h1:0MH3f8lZrflbUWXVxyBg/zviDFdGE062uKh5+fu8Vv0=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.4.0/go.mod h1:Vh68vYiHY5mPdekTr0ox0sALsqjoVy0w3Os278yX5SQ=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0 h1:BJee2iLkfRfl9lc7aFmBwkWxY/RI1RDdXepSF6y8TPE=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.28.0/go.mod h1:DIzlHs3DRscCIBU3Y9YSzPfScwnYnzfnCd4g8zA7bZc=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bEkIYOVMw4q1WJxIAGoFTrtYOzWuRQ=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y=
+go.opentelemetry.io/otel/log v0.4.0 h1:/vZ+3Utqh18e8TPjuc3ecg284078KWrR8BRz+PQAj3o=
+go.opentelemetry.io/otel/log v0.4.0/go.mod h1:DhGnQvky7pHy82MIRV43iXh3FlKN8UUKftn0KbLOq6I=
+go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
+go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
+go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/sdk/log v0.4.0 h1:1mMI22L82zLqf6KtkjrRy5BbagOTWdJsqMY/HSqILAA=
+go.opentelemetry.io/otel/sdk/log v0.4.0/go.mod h1:AYJ9FVF0hNOgAVzUG/ybg/QttnXhUePWAupmCqtdESo=
+go.opentelemetry.io/otel/sdk/metric v1.28.0 h1:OkuaKgKrgAbYrrY0t92c+cC+2F6hsFNnCQArXCKlg08=
+go.opentelemetry.io/otel/sdk/metric v1.28.0/go.mod h1:cWPjykihLAPvXKi4iZc1dpER3Jdq2Z0YLse3moQUCpg=
+go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
+go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/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-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo=
+google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
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=
@@ -325,29 +679,31 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/avro.v0 v0.0.0-20171217001914-a730b5802183/go.mod h1:FvqrFXt+jCsyQibeRv4xxEJBL5iG2DDW5aeJwzDiq4A=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/httprequest.v1 v1.2.1/go.mod h1:x2Otw96yda5+8+6ZeWwHIJTFkEHWP/qP8pJOzqEtWPM=
-gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
-gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
+gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
+rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
+rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
diff --git a/monitoring/ops/Dockerfile b/monitoring/ops/Dockerfile
index 2b9dbdf..14cd87e 100644
--- a/monitoring/ops/Dockerfile
+++ b/monitoring/ops/Dockerfile
@@ -1,26 +1,29 @@
# Build image
-FROM golang:1.20-buster as build
+FROM golang:1.21.5 as build
# Copy source
-RUN mkdir -p /starknet-monitoring/cmd
-COPY ./cmd/monitoring /starknet-monitoring/cmd/monitoring
-COPY ./pkg /starknet-monitoring/pkg
-COPY ./go.mod /starknet-monitoring/
-COPY ./go.sum /starknet-monitoring/
+RUN mkdir -p /build/starknet-monitoring/cmd
+COPY ./monitoring/cmd/monitoring /build/starknet-monitoring/cmd/monitoring
+COPY ./monitoring/pkg /build/starknet-monitoring/pkg
+COPY ./monitoring/go.mod /build/starknet-monitoring/
+COPY ./monitoring/go.sum /build/starknet-monitoring/
+
+# Copy relayer
+COPY ./relayer /build/relayer
# Compile binary
-WORKDIR /starknet-monitoring
+WORKDIR /build/starknet-monitoring
RUN go build -o ./monitoring ./cmd/monitoring/*.go
# Production image
-FROM ubuntu:20.04
+FROM ubuntu:22.04
RUN apt-get update && apt-get install -y ca-certificates
-COPY --from=build /starknet-monitoring/monitoring /monitoring
+COPY --from=build /build/starknet-monitoring/monitoring /monitoring
# Expose prometheus default port
EXPOSE 9090/tcp
diff --git a/monitoring/pkg/monitoring/config_chain.go b/monitoring/pkg/monitoring/config_chain.go
index 355ce3c..11c5bed 100644
--- a/monitoring/pkg/monitoring/config_chain.go
+++ b/monitoring/pkg/monitoring/config_chain.go
@@ -6,28 +6,34 @@ import (
"os"
"time"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
type StarknetConfig struct {
rpcEndpoint string
+ rpcApiKey string
networkName string
networkID string
chainID string
readTimeout time.Duration
pollInterval time.Duration
linkTokenAddress string
+ strkTokenAddress *felt.Felt
}
var _ relayMonitoring.ChainConfig = StarknetConfig{}
-func (s StarknetConfig) GetRPCEndpoint() string { return s.rpcEndpoint }
-func (s StarknetConfig) GetNetworkName() string { return s.networkName }
-func (s StarknetConfig) GetNetworkID() string { return s.networkID }
-func (s StarknetConfig) GetChainID() string { return s.chainID }
-func (s StarknetConfig) GetReadTimeout() time.Duration { return s.readTimeout }
-func (s StarknetConfig) GetPollInterval() time.Duration { return s.pollInterval }
-func (s StarknetConfig) GetLinkTokenAddress() string { return s.linkTokenAddress }
+func (s StarknetConfig) GetRPCEndpoint() string { return s.rpcEndpoint }
+func (s StarknetConfig) GetRPCApiKey() string { return s.rpcApiKey }
+func (s StarknetConfig) GetNetworkName() string { return s.networkName }
+func (s StarknetConfig) GetNetworkID() string { return s.networkID }
+func (s StarknetConfig) GetChainID() string { return s.chainID }
+func (s StarknetConfig) GetReadTimeout() time.Duration { return s.readTimeout }
+func (s StarknetConfig) GetPollInterval() time.Duration { return s.pollInterval }
+func (s StarknetConfig) GetLinkTokenAddress() string { return s.linkTokenAddress }
+func (s StarknetConfig) GetStrkTokenAddress() *felt.Felt { return s.strkTokenAddress }
func (s StarknetConfig) ToMapping() map[string]interface{} {
return map[string]interface{}{
@@ -54,6 +60,9 @@ func parseEnvVars(cfg *StarknetConfig) error {
if value, isPresent := os.LookupEnv("STARKNET_RPC_ENDPOINT"); isPresent {
cfg.rpcEndpoint = value
}
+ if value, isPresent := os.LookupEnv("STARKNET_RPC_API_KEY"); isPresent {
+ cfg.rpcApiKey = value
+ }
if value, isPresent := os.LookupEnv("STARKNET_NETWORK_NAME"); isPresent {
cfg.networkName = value
}
@@ -80,6 +89,13 @@ func parseEnvVars(cfg *StarknetConfig) error {
if value, isPresent := os.LookupEnv("STARKNET_PLI_TOKEN_ADDRESS"); isPresent {
cfg.linkTokenAddress = value
}
+ if value, isPresent := os.LookupEnv("STRK_TOKEN_ADDRESS"); isPresent {
+ feltValue, err := starknetutils.HexToFelt(value)
+ if err != nil {
+ return fmt.Errorf("failed to parse env var STRK_TOKEN_ADDRESS %w", err)
+ }
+ cfg.strkTokenAddress = feltValue
+ }
return nil
}
diff --git a/monitoring/pkg/monitoring/config_feed.go b/monitoring/pkg/monitoring/config_feed.go
index 2d58532..18a8d67 100644
--- a/monitoring/pkg/monitoring/config_feed.go
+++ b/monitoring/pkg/monitoring/config_feed.go
@@ -6,7 +6,7 @@ import (
"io"
"math/big"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
type StarknetFeedConfig struct {
diff --git a/monitoring/pkg/monitoring/config_node.go b/monitoring/pkg/monitoring/config_node.go
index 4adc1c4..ec3a1c9 100644
--- a/monitoring/pkg/monitoring/config_node.go
+++ b/monitoring/pkg/monitoring/config_node.go
@@ -5,8 +5,9 @@ import (
"fmt"
"io"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
"github.com/goplugin/plugin-libocr/offchainreporting2/types"
+
+ commonMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
type StarknetNodeConfig struct {
@@ -26,13 +27,13 @@ func (s StarknetNodeConfig) GetAccount() types.Account {
return types.Account(address)
}
-func StarknetNodesParser(buf io.ReadCloser) ([]relayMonitoring.NodeConfig, error) {
+func StarknetNodesParser(buf io.ReadCloser) ([]commonMonitoring.NodeConfig, error) {
rawNodes := []StarknetNodeConfig{}
decoder := json.NewDecoder(buf)
if err := decoder.Decode(&rawNodes); err != nil {
return nil, fmt.Errorf("unable to unmarshal nodes config data: %w", err)
}
- nodes := make([]relayMonitoring.NodeConfig, len(rawNodes))
+ nodes := make([]commonMonitoring.NodeConfig, len(rawNodes))
for i, rawNode := range rawNodes {
nodes[i] = rawNode
}
diff --git a/monitoring/pkg/monitoring/exporter_contract_balance.go b/monitoring/pkg/monitoring/exporter_contract_balance.go
new file mode 100644
index 0000000..50cd165
--- /dev/null
+++ b/monitoring/pkg/monitoring/exporter_contract_balance.go
@@ -0,0 +1,79 @@
+package monitoring
+
+import (
+ "context"
+ "math/big"
+ "sync"
+
+ commonMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+)
+
+func NewNodeBalancesExporterFactory(log commonMonitoring.Logger, metrics Metrics) commonMonitoring.ExporterFactory {
+ return &nodeBalancesExporterFactory{
+ log,
+ metrics,
+ }
+}
+
+type nodeBalancesExporterFactory struct {
+ log commonMonitoring.Logger
+ metrics Metrics
+}
+
+func (f *nodeBalancesExporterFactory) NewExporter(params commonMonitoring.ExporterParams) (commonMonitoring.Exporter, error) {
+ return &nodeBalancesExporter{
+ log: f.log,
+ metrics: f.metrics,
+ chainConfig: params.ChainConfig,
+ }, nil
+}
+
+type nodeBalancesExporter struct {
+ log commonMonitoring.Logger
+ metrics Metrics
+ chainConfig commonMonitoring.ChainConfig
+ addrsSet []ContractAddressWithBalance
+ addrsMu sync.Mutex
+}
+
+func (e *nodeBalancesExporter) Export(ctx context.Context, data interface{}) {
+ balanceEnvelope, isBalanceEnvelope := data.(BalanceEnvelope)
+ if !isBalanceEnvelope {
+ return
+ }
+
+ decimals := balanceEnvelope.Decimals
+ divisor := new(big.Int).Exp(new(big.Int).SetUint64(10), decimals, nil) // 10^(decimals)
+
+ for _, c := range balanceEnvelope.Contracts {
+ balanceAns := new(big.Int).Div(c.Balance, divisor)
+
+ e.metrics.SetBalance(
+ toFloat64(balanceAns),
+ c.Address.String(),
+ c.Name,
+ e.chainConfig.GetNetworkID(),
+ e.chainConfig.GetNetworkName(),
+ e.chainConfig.GetChainID())
+ }
+
+ e.addrsMu.Lock()
+ defer e.addrsMu.Unlock()
+
+ e.addrsSet = balanceEnvelope.Contracts
+
+}
+
+func (e *nodeBalancesExporter) Cleanup(_ context.Context) {
+ e.addrsMu.Lock()
+ defer e.addrsMu.Unlock()
+
+ for _, c := range e.addrsSet {
+ e.metrics.CleanupBalance(c.Address.String(), c.Name, e.chainConfig.GetNetworkID(), e.chainConfig.GetNetworkName(), e.chainConfig.GetChainID())
+ }
+}
+
+func toFloat64(bignum *big.Int) float64 {
+ val, _ := new(big.Float).SetInt(bignum).Float64()
+ return val
+}
diff --git a/monitoring/pkg/monitoring/exporter_prometheus.go b/monitoring/pkg/monitoring/exporter_prometheus.go
index 168d090..5da664d 100644
--- a/monitoring/pkg/monitoring/exporter_prometheus.go
+++ b/monitoring/pkg/monitoring/exporter_prometheus.go
@@ -5,7 +5,7 @@ import (
"fmt"
"sync"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
// NewPrometheusExporterFactory builds an implementation of the Exporter for prometheus.
@@ -88,7 +88,7 @@ func (p *prometheusExporter) Cleanup(_ context.Context) {
p.addressesMu.Lock()
defer p.addressesMu.Unlock()
for address := range p.addressesSet {
- p.metrics.Cleanup(
+ p.metrics.CleanupProxy(
address,
p.feedConfig.GetContractAddress(),
p.chainConfig.GetChainID(),
diff --git a/monitoring/pkg/monitoring/exporter_transmission_details.go b/monitoring/pkg/monitoring/exporter_transmission_details.go
new file mode 100644
index 0000000..4708ec4
--- /dev/null
+++ b/monitoring/pkg/monitoring/exporter_transmission_details.go
@@ -0,0 +1,107 @@
+package monitoring
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+)
+
+// NewPrometheusExporterFactory builds an implementation of the Exporter for prometheus.
+func NewTransmissionDetailsExporterFactory(
+ metrics Metrics,
+) relayMonitoring.ExporterFactory {
+ return &transmissionDetailsExporterFactory{
+ metrics,
+ }
+}
+
+type transmissionDetailsExporterFactory struct {
+ metrics Metrics
+}
+
+func (p *transmissionDetailsExporterFactory) NewExporter(
+ params relayMonitoring.ExporterParams,
+) (relayMonitoring.Exporter, error) {
+ starknetFeedConfig, ok := params.FeedConfig.(StarknetFeedConfig)
+ if !ok {
+ return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", params.FeedConfig)
+ }
+ return &transmissionDetailsExporter{
+ params.ChainConfig,
+ starknetFeedConfig,
+ p.metrics,
+ }, nil
+}
+
+type transmissionDetailsExporter struct {
+ chainConfig relayMonitoring.ChainConfig
+ feedConfig StarknetFeedConfig
+ metrics Metrics
+}
+
+func (p *transmissionDetailsExporter) Export(ctx context.Context, data interface{}) {
+ transmissionsEnvelope, found := data.(TransmissionsEnvelope)
+ if !found {
+ return
+ }
+
+ for _, t := range transmissionsEnvelope.Transmissions {
+ // gas price
+ divisor := new(big.Int).Exp(new(big.Int).SetUint64(10), new(big.Int).SetUint64(18), nil) // 10^18
+ gasPriceInSTRK := new(big.Int).Div(t.GasPrice, divisor)
+ p.metrics.SetTransmissionGasPrice(
+ toFloat64(gasPriceInSTRK),
+ p.feedConfig.ContractAddress,
+ p.feedConfig.GetID(),
+ p.chainConfig.GetChainID(),
+ p.feedConfig.GetContractStatus(),
+ p.feedConfig.GetContractType(),
+ p.feedConfig.Name,
+ p.feedConfig.Path,
+ p.chainConfig.GetNetworkID(),
+ p.chainConfig.GetNetworkName(),
+ )
+
+ // observation length
+ observationLength := float64(t.ObservationLength)
+ p.metrics.SetReportObservations(
+ observationLength,
+ p.feedConfig.ContractAddress,
+ p.feedConfig.GetID(),
+ p.chainConfig.GetChainID(),
+ p.feedConfig.GetContractStatus(),
+ p.feedConfig.GetContractType(),
+ p.feedConfig.Name,
+ p.feedConfig.Path,
+ p.chainConfig.GetNetworkID(),
+ p.chainConfig.GetNetworkName(),
+ )
+ }
+}
+
+func (p *transmissionDetailsExporter) Cleanup(_ context.Context) {
+ p.metrics.CleanupTransmissionGasPrice(
+ p.feedConfig.GetContractAddress(),
+ p.feedConfig.GetID(),
+ p.chainConfig.GetChainID(),
+ p.feedConfig.GetContractStatus(),
+ p.feedConfig.GetContractType(),
+ p.feedConfig.GetName(),
+ p.feedConfig.GetPath(),
+ p.chainConfig.GetNetworkID(),
+ p.chainConfig.GetNetworkName(),
+ )
+ p.metrics.CleanupReportObservations(
+ p.feedConfig.GetContractAddress(),
+ p.feedConfig.GetID(),
+ p.chainConfig.GetChainID(),
+ p.feedConfig.GetContractStatus(),
+ p.feedConfig.GetContractType(),
+ p.feedConfig.GetName(),
+ p.feedConfig.GetPath(),
+ p.chainConfig.GetNetworkID(),
+ p.chainConfig.GetNetworkName(),
+ )
+}
diff --git a/monitoring/pkg/monitoring/exporter_transmission_details_test.go b/monitoring/pkg/monitoring/exporter_transmission_details_test.go
new file mode 100644
index 0000000..aeba508
--- /dev/null
+++ b/monitoring/pkg/monitoring/exporter_transmission_details_test.go
@@ -0,0 +1,97 @@
+package monitoring
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/goplugin/plugin-starknet/monitoring/pkg/monitoring/mocks"
+
+ commonMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+)
+
+func TestTransmissionDetailsExporter(t *testing.T) {
+ chainConfig := generateChainConfig()
+ feedConfig := generateFeedConfig()
+
+ mockMetrics := mocks.NewMetrics(t)
+ factory := NewTransmissionDetailsExporterFactory(mockMetrics)
+
+ gasPrice, ok := new(big.Int).SetString("10000000000000000000", 10)
+ require.True(t, ok)
+
+ envelope := TransmissionsEnvelope{
+ Transmissions: []TransmissionInfo{{
+ GasPrice: gasPrice, // 10 STRK (10^19 FRI)
+ ObservationLength: 123,
+ },
+ },
+ }
+
+ mockMetrics.On(
+ "SetTransmissionGasPrice",
+ float64(10),
+ feedConfig.ContractAddress,
+ feedConfig.GetID(),
+ chainConfig.GetChainID(),
+ feedConfig.GetContractStatus(),
+ feedConfig.GetContractType(),
+ feedConfig.Name,
+ feedConfig.Path,
+ chainConfig.GetNetworkID(),
+ chainConfig.GetNetworkName(),
+ ).Once()
+
+ mockMetrics.On(
+ "SetReportObservations",
+ float64(123),
+ feedConfig.ContractAddress,
+ feedConfig.GetID(),
+ chainConfig.GetChainID(),
+ feedConfig.GetContractStatus(),
+ feedConfig.GetContractType(),
+ feedConfig.Name,
+ feedConfig.Path,
+ chainConfig.GetNetworkID(),
+ chainConfig.GetNetworkName(),
+ ).Once()
+
+ exporter, err := factory.NewExporter(commonMonitoring.ExporterParams{
+ ChainConfig: chainConfig,
+ FeedConfig: feedConfig,
+ })
+ require.NoError(t, err)
+
+ exporter.Export(context.Background(), envelope)
+
+ // cleanup
+ mockMetrics.On(
+ "CleanupReportObservations",
+ feedConfig.ContractAddress,
+ feedConfig.GetID(),
+ chainConfig.GetChainID(),
+ feedConfig.GetContractStatus(),
+ feedConfig.GetContractType(),
+ feedConfig.Name,
+ feedConfig.Path,
+ chainConfig.GetNetworkID(),
+ chainConfig.GetNetworkName(),
+ ).Once()
+ mockMetrics.On(
+ "CleanupTransmissionGasPrice",
+ feedConfig.ContractAddress,
+ feedConfig.GetID(),
+ chainConfig.GetChainID(),
+ feedConfig.GetContractStatus(),
+ feedConfig.GetContractType(),
+ feedConfig.Name,
+ feedConfig.Path,
+ chainConfig.GetNetworkID(),
+ chainConfig.GetNetworkName(),
+ ).Once()
+
+ exporter.Cleanup(context.Background())
+
+}
diff --git a/monitoring/pkg/monitoring/metrics.go b/monitoring/pkg/monitoring/metrics.go
index 74d20bc..f5fba51 100644
--- a/monitoring/pkg/monitoring/metrics.go
+++ b/monitoring/pkg/monitoring/metrics.go
@@ -3,17 +3,61 @@ package monitoring
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
// Metrics is an interface for prometheus metrics. Makes testing easier.
+//
+//go:generate mockery --name Metrics --output ./mocks/
type Metrics interface {
+ SetTransmissionGasPrice(answer float64, contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
+ CleanupTransmissionGasPrice(contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
+ SetReportObservations(answer float64, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
+ CleanupReportObservations(accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
SetProxyAnswersRaw(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
SetProxyAnswers(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
- Cleanup(proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
+ CleanupProxy(proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
+ SetBalance(answer float64, contractAddress, alias, networkId, networkName, chainID string)
+ CleanupBalance(contractAddress, alias, networkId, networkName, chainID string)
}
var (
+ transmissionGasPrice = promauto.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "starknet_transmission_gas_price",
+ Help: "Reports gas price (units STRK) reported with transmission",
+ },
+ []string{
+ "contract_address",
+ "feed_id",
+ "chain_id",
+ "contract_status",
+ "contract_type",
+ "feed_name",
+ "feed_path",
+ "network_id",
+ "network_name",
+ },
+ )
+ reportObservations = promauto.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "report_observations",
+ Help: "Reports # of observations included in a transmission report",
+ },
+ []string{
+ // uses "account_address" instead of "contract_address" for consistency with solana dashboards
+ "account_address",
+ "feed_id",
+ "chain_id",
+ "contract_status",
+ "contract_type",
+ "feed_name",
+ "feed_path",
+ "network_id",
+ "network_name",
+ },
+ )
proxyAnswersRaw = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "proxy_answers_raw",
@@ -28,6 +72,13 @@ var (
},
[]string{"proxy_contract_address", "feed_id", "chain_id", "contract_status", "contract_type", "feed_name", "feed_path", "network_id", "network_name"},
)
+ contractBalance = promauto.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "strk_contract_balance",
+ Help: "Reports the latest STRK balance of a contract address",
+ },
+ []string{"contract_address", "alias", "network_id", "network_name", "chain_id"},
+ )
)
// NewMetrics does wisott
@@ -39,6 +90,91 @@ type defaultMetrics struct {
log relayMonitoring.Logger
}
+func (d *defaultMetrics) SetTransmissionGasPrice(answer float64, contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
+ transmissionGasPrice.With(prometheus.Labels{
+ "contract_address": contractAddress,
+ "feed_id": feedID,
+ "chain_id": chainID,
+ "contract_status": contractStatus,
+ "contract_type": contractType,
+ "feed_name": feedName,
+ "feed_path": feedPath,
+ "network_id": networkID,
+ "network_name": networkName,
+ }).Set(answer)
+}
+
+func (d *defaultMetrics) CleanupTransmissionGasPrice(contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
+ labels := prometheus.Labels{
+ "contract_address": contractAddress,
+ "feed_id": feedID,
+ "chain_id": chainID,
+ "contract_status": contractStatus,
+ "contract_type": contractType,
+ "feed_name": feedName,
+ "feed_path": feedPath,
+ "network_id": networkID,
+ "network_name": networkName,
+ }
+ if !transmissionGasPrice.Delete(labels) {
+ d.log.Errorw("failed to delete metric", "name", "starknet_transmission_gas_price", "labels", labels)
+ }
+}
+
+func (d *defaultMetrics) SetBalance(answer float64, contractAddress, alias, networkId, networkName, chainID string) {
+ contractBalance.With(prometheus.Labels{
+ "contract_address": contractAddress,
+ "alias": alias,
+ "network_id": networkId,
+ "network_name": networkName,
+ "chain_id": chainID,
+ }).Set(answer)
+}
+
+func (d *defaultMetrics) CleanupBalance(contractAddress, alias, networkId, networkName, chainID string) {
+ labels := prometheus.Labels{
+ "contract_address": contractAddress,
+ "alias": alias,
+ "network_id": networkId,
+ "network_name": networkName,
+ "chain_id": chainID,
+ }
+ if !contractBalance.Delete(labels) {
+ d.log.Errorw("failed to delete metric", "name", "strk_contract_balance", "labels", labels)
+ }
+}
+
+func (d *defaultMetrics) SetReportObservations(answer float64, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
+ reportObservations.With(prometheus.Labels{
+ "account_address": accountAddress,
+ "feed_id": feedID,
+ "chain_id": chainID,
+ "contract_status": contractStatus,
+ "contract_type": contractType,
+ "feed_name": feedName,
+ "feed_path": feedPath,
+ "network_id": networkID,
+ "network_name": networkName,
+ }).Set(answer)
+}
+
+func (d *defaultMetrics) CleanupReportObservations(accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
+ labels := prometheus.Labels{
+ "account_address": accountAddress,
+ "feed_id": feedID,
+ "chain_id": chainID,
+ "contract_status": contractStatus,
+ "contract_type": contractType,
+ "feed_name": feedName,
+ "feed_path": feedPath,
+ "network_id": networkID,
+ "network_name": networkName,
+ }
+ if !reportObservations.Delete(labels) {
+ d.log.Errorw("failed to delete metric", "name", "report_observations", "labels", labels)
+ }
+}
+
func (d *defaultMetrics) SetProxyAnswersRaw(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
proxyAnswersRaw.With(prometheus.Labels{
"proxy_contract_address": proxyContractAddress,
@@ -67,7 +203,7 @@ func (d *defaultMetrics) SetProxyAnswers(answer float64, proxyContractAddress, f
}).Set(answer)
}
-func (d *defaultMetrics) Cleanup(
+func (d *defaultMetrics) CleanupProxy(
proxyContractAddress, feedID, chainID, contractStatus, contractType string,
feedName, feedPath, networkID, networkName string,
) {
diff --git a/monitoring/pkg/monitoring/mocks/Metrics.go b/monitoring/pkg/monitoring/mocks/Metrics.go
new file mode 100644
index 0000000..fa9e1bb
--- /dev/null
+++ b/monitoring/pkg/monitoring/mocks/Metrics.go
@@ -0,0 +1,69 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// Metrics is an autogenerated mock type for the Metrics type
+type Metrics struct {
+ mock.Mock
+}
+
+// CleanupBalance provides a mock function with given fields: contractAddress, alias, networkId, networkName, chainID
+func (_m *Metrics) CleanupBalance(contractAddress string, alias string, networkId string, networkName string, chainID string) {
+ _m.Called(contractAddress, alias, networkId, networkName, chainID)
+}
+
+// CleanupProxy provides a mock function with given fields: proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) CleanupProxy(proxyContractAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// CleanupReportObservations provides a mock function with given fields: accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) CleanupReportObservations(accountAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// CleanupTransmissionGasPrice provides a mock function with given fields: contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) CleanupTransmissionGasPrice(contractAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// SetBalance provides a mock function with given fields: answer, contractAddress, alias, networkId, networkName, chainID
+func (_m *Metrics) SetBalance(answer float64, contractAddress string, alias string, networkId string, networkName string, chainID string) {
+ _m.Called(answer, contractAddress, alias, networkId, networkName, chainID)
+}
+
+// SetProxyAnswers provides a mock function with given fields: answer, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) SetProxyAnswers(answer float64, proxyContractAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(answer, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// SetProxyAnswersRaw provides a mock function with given fields: answer, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) SetProxyAnswersRaw(answer float64, proxyContractAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(answer, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// SetReportObservations provides a mock function with given fields: answer, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) SetReportObservations(answer float64, accountAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(answer, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// SetTransmissionGasPrice provides a mock function with given fields: answer, contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName
+func (_m *Metrics) SetTransmissionGasPrice(answer float64, contractAddress string, feedID string, chainID string, contractStatus string, contractType string, feedName string, feedPath string, networkID string, networkName string) {
+ _m.Called(answer, contractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName)
+}
+
+// NewMetrics creates a new instance of Metrics. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewMetrics(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *Metrics {
+ mock := &Metrics{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/monitoring/pkg/monitoring/monitor.go b/monitoring/pkg/monitoring/monitor.go
new file mode 100644
index 0000000..3684be1
--- /dev/null
+++ b/monitoring/pkg/monitoring/monitor.go
@@ -0,0 +1,182 @@
+package monitoring
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/goplugin/plugin-common/pkg/logger"
+ commonMonitor "github.com/goplugin/plugin-common/pkg/monitoring"
+ "github.com/goplugin/plugin-common/pkg/monitoring/config"
+ "github.com/goplugin/plugin-common/pkg/services"
+)
+
+// Builds monitor instance with only the prometheus exporter.
+// Does not contain kafka exporter.
+func NewMonitorPrometheusOnly(
+ stopCh services.StopRChan,
+ log commonMonitor.Logger,
+ chainConfig commonMonitor.ChainConfig,
+ envelopeSourceFactory commonMonitor.SourceFactory,
+ txResultsSourceFactory commonMonitor.SourceFactory,
+ feedsParser commonMonitor.FeedsParser,
+ nodesParser commonMonitor.NodesParser,
+) (*commonMonitor.Monitor, error) {
+ cfg, err := ParseWithoutKafka()
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse generic configuration: %w", err)
+ }
+
+ metrics := commonMonitor.NewMetrics(logger.With(log, "component", "metrics"))
+ chainMetrics := commonMonitor.NewChainMetrics(chainConfig)
+
+ sourceFactories := []commonMonitor.SourceFactory{envelopeSourceFactory, txResultsSourceFactory}
+
+ prometheusExporterFactory := commonMonitor.NewPrometheusExporterFactory(
+ logger.With(log, "component", "prometheus-exporter"),
+ metrics,
+ )
+
+ exporterFactories := []commonMonitor.ExporterFactory{prometheusExporterFactory}
+
+ rddSource := commonMonitor.NewRDDSource(
+ cfg.Feeds.URL, feedsParser, cfg.Feeds.IgnoreIDs,
+ cfg.Nodes.URL, nodesParser,
+ logger.With(log, "component", "rdd-source"),
+ )
+
+ rddPoller := commonMonitor.NewSourcePoller(
+ rddSource,
+ logger.With(log, "component", "rdd-poller"),
+ cfg.Feeds.RDDPollInterval,
+ cfg.Feeds.RDDReadTimeout,
+ 0, // no buffering!
+ )
+
+ manager := commonMonitor.NewManager(
+ logger.With(log, "component", "manager"),
+ rddPoller,
+ )
+
+ // Configure HTTP server
+ httpServer := commonMonitor.NewHTTPServer(stopCh, cfg.HTTP.Address, logger.With(log, "component", "http-server"))
+ httpServer.Handle("/metrics", metrics.HTTPHandler())
+ httpServer.Handle("/debug", manager.HTTPHandler())
+ // Required for k8s.
+ httpServer.Handle("/health", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ }))
+
+ return &commonMonitor.Monitor{
+ StopCh: stopCh,
+ ChainConfig: chainConfig,
+ Config: cfg,
+ Log: log,
+ // no kafka
+ Producer: nil,
+ Metrics: metrics,
+ ChainMetrics: chainMetrics,
+ // no kafka
+ SchemaRegistry: nil,
+ SourceFactories: sourceFactories,
+ ExporterFactories: exporterFactories,
+
+ RDDSource: rddSource,
+ RDDPoller: rddPoller,
+
+ Manager: manager,
+
+ HTTPServer: httpServer,
+ }, nil
+}
+
+type MyConfig = config.Config
+
+func ParseWithoutKafka() (MyConfig, error) {
+ cfg := MyConfig{}
+
+ if err := parseConfigEnvVars(&cfg); err != nil {
+ return cfg, err
+ }
+
+ applyConfigDefaults(&cfg)
+
+ err := validateConfigWithoutKafka(cfg)
+
+ return cfg, err
+}
+
+func applyConfigDefaults(cfg *MyConfig) {
+ if cfg.Feeds.RDDReadTimeout == 0 {
+ cfg.Feeds.RDDReadTimeout = 1 * time.Second
+ }
+ if cfg.Feeds.RDDPollInterval == 0 {
+ cfg.Feeds.RDDPollInterval = 10 * time.Second
+ }
+}
+
+func parseConfigEnvVars(cfg *MyConfig) error {
+ if value, isPresent := os.LookupEnv("FEEDS_URL"); isPresent {
+ cfg.Feeds.URL = value
+ }
+ if value, isPresent := os.LookupEnv("FEEDS_RDD_READ_TIMEOUT"); isPresent {
+ readTimeout, err := time.ParseDuration(value)
+ if err != nil {
+ return fmt.Errorf("failed to parse env var FEEDS_RDD_READ_TIMEOUT, see https://pkg.go.dev/time#ParseDuration: %w", err)
+ }
+ cfg.Feeds.RDDReadTimeout = readTimeout
+ }
+ if value, isPresent := os.LookupEnv("FEEDS_RDD_POLL_INTERVAL"); isPresent {
+ pollInterval, err := time.ParseDuration(value)
+ if err != nil {
+ return fmt.Errorf("failed to parse env var FEEDS_RDD_POLL_INTERVAL, see https://pkg.go.dev/time#ParseDuration: %w", err)
+ }
+ cfg.Feeds.RDDPollInterval = pollInterval
+ }
+ if value, isPresent := os.LookupEnv("FEEDS_IGNORE_IDS"); isPresent {
+ ids := strings.Split(value, ",")
+ for _, id := range ids {
+ if id == "" {
+ continue
+ }
+ cfg.Feeds.IgnoreIDs = append(cfg.Feeds.IgnoreIDs, strings.TrimSpace(id))
+ }
+ }
+ if value, isPresent := os.LookupEnv("NODES_URL"); isPresent {
+ cfg.Nodes.URL = value
+ }
+
+ if value, isPresent := os.LookupEnv("HTTP_ADDRESS"); isPresent {
+ cfg.HTTP.Address = value
+ }
+
+ return nil
+}
+
+func validateConfigWithoutKafka(cfg MyConfig) error {
+ // Required config
+ for envVarName, currentValue := range map[string]string{
+ "FEEDS_URL": cfg.Feeds.URL,
+ "NODES_URL": cfg.Nodes.URL,
+
+ "HTTP_ADDRESS": cfg.HTTP.Address,
+ } {
+ if currentValue == "" {
+ return fmt.Errorf("'%s' env var is required", envVarName)
+ }
+ }
+ // Validate URLs.
+ for envVarName, currentValue := range map[string]string{
+ "FEEDS_URL": cfg.Feeds.URL,
+ "NODES_URL": cfg.Nodes.URL,
+ } {
+ if _, err := url.ParseRequestURI(currentValue); err != nil {
+ return fmt.Errorf("%s='%s' is not a valid URL: %w", envVarName, currentValue, err)
+ }
+ }
+
+ return nil
+}
diff --git a/monitoring/pkg/monitoring/source_contract_balance.go b/monitoring/pkg/monitoring/source_contract_balance.go
new file mode 100644
index 0000000..78a853a
--- /dev/null
+++ b/monitoring/pkg/monitoring/source_contract_balance.go
@@ -0,0 +1,92 @@
+package monitoring
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ commonMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/erc20"
+)
+
+type ContractAddress struct {
+ Address *felt.Felt
+ Name string
+}
+
+type ContractAddressWithBalance struct {
+ ContractAddress
+ Balance *big.Int
+}
+
+type BalanceEnvelope struct {
+ Contracts []ContractAddressWithBalance
+ Decimals *big.Int
+}
+
+func NewContractAddress(address string, name string) (ContractAddress, error) {
+ ans := ContractAddress{}
+ addr, err := starknetutils.HexToFelt(address)
+ if err != nil {
+ return ans, fmt.Errorf("error parsing contract address: %w", err)
+ }
+ ans.Address = addr
+ ans.Name = name
+ return ans, nil
+}
+
+type nodeBalancesSourceFactory struct {
+ erc20Reader erc20.ERC20Reader
+}
+
+func NewNodeBalancesSourceFactory(erc20Reader erc20.ERC20Reader) *nodeBalancesSourceFactory {
+ return &nodeBalancesSourceFactory{
+ erc20Reader: erc20Reader,
+ }
+}
+
+func (f *nodeBalancesSourceFactory) NewSource(
+ _ commonMonitoring.ChainConfig,
+ rddNodes []commonMonitoring.NodeConfig,
+) (commonMonitoring.Source, error) {
+ var addrs []ContractAddress
+
+ for _, n := range rddNodes {
+ addr, err := NewContractAddress(string(n.GetAccount()), n.GetName())
+ if err != nil {
+ return nil, err
+ }
+ addrs = append(addrs, addr)
+ }
+
+ return &contractBalancesSource{erc20Reader: f.erc20Reader, contracts: addrs}, nil
+}
+
+func (f *nodeBalancesSourceFactory) GetType() string {
+ return "nodeBalances"
+}
+
+// contract balances sources can be potentially reused for other contracts (not just the node account contracts)
+type contractBalancesSource struct {
+ erc20Reader erc20.ERC20Reader
+ contracts []ContractAddress
+}
+
+func (s *contractBalancesSource) Fetch(ctx context.Context) (interface{}, error) {
+ var cAns []ContractAddressWithBalance
+ for _, c := range s.contracts {
+ balance, err := s.erc20Reader.BalanceOf(ctx, c.Address)
+ if err != nil {
+ return nil, fmt.Errorf("could not fetch address balance %w", err)
+ }
+ cAns = append(cAns, ContractAddressWithBalance{c, balance})
+ }
+ dAns, err := s.erc20Reader.Decimals(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("could not fetch decimals %w", err)
+ }
+
+ return BalanceEnvelope{Contracts: cAns, Decimals: dAns}, nil
+}
diff --git a/monitoring/pkg/monitoring/source_contract_balance_test.go b/monitoring/pkg/monitoring/source_contract_balance_test.go
new file mode 100644
index 0000000..f19cf5b
--- /dev/null
+++ b/monitoring/pkg/monitoring/source_contract_balance_test.go
@@ -0,0 +1,50 @@
+package monitoring
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ erc20Mocks "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/erc20/mocks"
+)
+
+func TestContractBalancesSource(t *testing.T) {
+ chainConfig := generateChainConfig()
+ nodeConfig := generateNodeConfig()
+
+ erc20Reader := erc20Mocks.NewERC20Reader(t)
+
+ for _, x := range nodeConfig {
+ nodeAddressFelt, err := starknetutils.HexToFelt(string(x.GetAccount()))
+ require.NoError(t, err)
+
+ erc20Reader.On(
+ "BalanceOf",
+ mock.Anything, // ctx
+ nodeAddressFelt, // address
+ ).Return(new(big.Int).SetUint64(777), nil)
+ }
+
+ erc20Reader.On(
+ "Decimals",
+ mock.Anything, // ctx
+ ).Return(new(big.Int).SetUint64(18), nil)
+
+ factory := NewNodeBalancesSourceFactory(erc20Reader)
+ source, err := factory.NewSource(chainConfig, nodeConfig)
+ require.NoError(t, err)
+ rawBalanceEnvelope, err := source.Fetch(context.Background())
+ require.NoError(t, err)
+ balanceEnvelope, ok := rawBalanceEnvelope.(BalanceEnvelope)
+ require.True(t, ok)
+
+ require.Equal(t, balanceEnvelope.Decimals.Uint64(), uint64(18))
+
+ require.Equal(t, balanceEnvelope.Contracts[0].Balance.Uint64(), uint64(777))
+ require.Equal(t, balanceEnvelope.Contracts[1].Balance.Uint64(), uint64(777))
+
+}
diff --git a/monitoring/pkg/monitoring/source_envelope.go b/monitoring/pkg/monitoring/source_envelope.go
index 090ae6e..0921eb1 100644
--- a/monitoring/pkg/monitoring/source_envelope.go
+++ b/monitoring/pkg/monitoring/source_envelope.go
@@ -2,17 +2,19 @@ package monitoring
import (
"context"
+ "errors"
"fmt"
"math/big"
"sync"
- junotypes "github.com/NethermindEth/juno/pkg/types"
- "github.com/dontpanicdao/caigo"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
- relayUtils "github.com/goplugin/plugin-relay/pkg/utils"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
"github.com/goplugin/plugin-libocr/offchainreporting2/types"
"go.uber.org/multierr"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+ relayUtils "github.com/goplugin/plugin-common/pkg/utils"
+
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
"github.com/goplugin/plugin-starknet/relayer/pkg/starknet"
)
@@ -37,9 +39,17 @@ func (s *envelopeSourceFactory) NewSource(
if !ok {
return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", feedConfig)
}
+ contractAddress, err := starknetutils.HexToFelt(feedConfig.GetContractAddress())
+ if err != nil {
+ return nil, err
+ }
+ linkTokenAddress, err := starknetutils.HexToFelt(starknetChainConfig.GetLinkTokenAddress())
+ if err != nil {
+ return nil, err
+ }
return &envelopeSource{
- feedConfig.GetContractAddress(),
- starknetChainConfig.GetLinkTokenAddress(),
+ contractAddress,
+ linkTokenAddress,
s.ocr2Reader,
}, nil
}
@@ -49,8 +59,8 @@ func (s *envelopeSourceFactory) GetType() string {
}
type envelopeSource struct {
- contractAddress string
- linkTokenAddress string
+ contractAddress *felt.Felt
+ linkTokenAddress *felt.Felt
ocr2Reader ocr2.OCR2Reader
}
@@ -65,13 +75,11 @@ func (s *envelopeSource) Fetch(ctx context.Context) (interface{}, error) {
envelopeMu.Lock()
defer envelopeMu.Unlock()
if err != nil {
- envelopeErr = multierr.Combine(envelopeErr, fmt.Errorf("fetchLatestNewTransmissionEvent failed: %w", err))
+ envelopeErr = errors.Join(envelopeErr, fmt.Errorf("fetchLatestNewTransmissionEvent failed: %w", err))
return
}
envelope.BlockNumber = latestRoundData.BlockNumber
- if newTransmissionEvent.Transmitter != nil {
- envelope.Transmitter = types.Account(newTransmissionEvent.Transmitter.String())
- }
+ envelope.Transmitter = types.Account(newTransmissionEvent.Transmitter.String())
envelope.AggregatorRoundID = latestRoundData.RoundID
envelope.ConfigDigest = newTransmissionEvent.ConfigDigest
envelope.Epoch = newTransmissionEvent.Epoch
@@ -118,7 +126,7 @@ func (s *envelopeSource) Fetch(ctx context.Context) (interface{}, error) {
return envelope, envelopeErr
}
-func (s *envelopeSource) fetchLatestNewTransmissionEvent(ctx context.Context, contractAddress string) (
+func (s *envelopeSource) fetchLatestNewTransmissionEvent(ctx context.Context, contractAddress *felt.Felt) (
latestRound ocr2.RoundData,
transmission ocr2.NewTransmissionEvent,
err error,
@@ -144,7 +152,7 @@ func (s *envelopeSource) fetchLatestNewTransmissionEvent(ctx context.Context, co
return latestRound, transmission, fmt.Errorf("no new_trasmission event found to correspond with the round id %d in block %d", latestRound.RoundID, latestRound.BlockNumber)
}
-func (s *envelopeSource) fetchContractConfig(ctx context.Context, contractAddress string) (config ocr2.ContractConfig, err error) {
+func (s *envelopeSource) fetchContractConfig(ctx context.Context, contractAddress *felt.Felt) (config ocr2.ContractConfig, err error) {
configDetails, err := s.ocr2Reader.LatestConfigDetails(ctx, contractAddress)
if err != nil {
return config, fmt.Errorf("couldn't fetch latest config details for contract '%s': %w", contractAddress, err)
@@ -158,23 +166,18 @@ func (s *envelopeSource) fetchContractConfig(ctx context.Context, contractAddres
var zeroBigInt = big.NewInt(0)
-func (s *envelopeSource) fetchLinkBalance(ctx context.Context, linkTokenAddress, contractAddress string) (*big.Int, error) {
+func (s *envelopeSource) fetchLinkBalance(ctx context.Context, linkTokenAddress, contractAddress *felt.Felt) (*big.Int, error) {
results, err := s.ocr2Reader.BaseReader().CallContract(ctx, starknet.CallOps{
ContractAddress: linkTokenAddress,
- Selector: "balanceOf",
- Calldata: []string{
- caigo.HexToBN(contractAddress).String(),
- },
+ Selector: starknetutils.GetSelectorFromNameFelt("balance_of"),
+ Calldata: []*felt.Felt{contractAddress},
})
if err != nil {
- return nil, fmt.Errorf("failed call to ECR20 contract, balanceOf method: %w", err)
+ return nil, fmt.Errorf("failed call to ECR20 contract, balance_of method: %w", err)
}
if len(results) < 1 {
- return nil, fmt.Errorf("insufficient data from balanceOf '%v': %w", results, err)
- }
- linkBalance := junotypes.HexToFelt(results[0]).Big()
- if linkBalance.Cmp(zeroBigInt) == 0 {
- return nil, fmt.Errorf("contract's PLI balance should not be zero")
+ return nil, fmt.Errorf("insufficient data from balance_of '%v': %w", results, err)
}
+ linkBalance := results[0].BigInt(big.NewInt(0))
return linkBalance, nil
}
diff --git a/monitoring/pkg/monitoring/source_envelope_test.go b/monitoring/pkg/monitoring/source_envelope_test.go
index 9b14773..9aeeb50 100644
--- a/monitoring/pkg/monitoring/source_envelope_test.go
+++ b/monitoring/pkg/monitoring/source_envelope_test.go
@@ -6,13 +6,14 @@ import (
"testing"
"time"
- "github.com/dontpanicdao/caigo"
- caigotypes "github.com/dontpanicdao/caigo/types"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
"github.com/goplugin/plugin-libocr/offchainreporting2/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
ocr2Mocks "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2/mocks"
@@ -27,46 +28,81 @@ func TestEnvelopeSource(t *testing.T) {
chainConfig := generateChainConfig()
feedConfig := generateFeedConfig()
+ feedContractAddressFelt, err := starknetutils.HexToFelt(feedConfig.ContractAddress)
+ require.NoError(t, err)
+
+ transmitterContractAddressFelt, err := starknetutils.HexToFelt("0x16715b5cc943835f196b7caf5a8aeb0e85b3f975dc43c14c90d0376e87eead1")
+ require.NoError(t, err)
+
+ ocr2ClientNewTransmissionEventAtResponse := []ocr2.NewTransmissionEvent{
+ {
+ RoundId: 0xf5b,
+ LatestAnswer: bigIntFromString("-900000000"),
+ Transmitter: transmitterContractAddressFelt,
+ LatestTimestamp: time.Date(2022, time.September, 27, 18, 51, 0, 0, time.Local),
+ Observers: []uint8{0x1, 0x2, 0x3, 0x4},
+ ObservationsLen: 0x4,
+ Observations: []*big.Int{
+ bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
+ bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
+ bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
+ bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
+ },
+ JuelsPerFeeCoin: big.NewInt(451000),
+ GasPrice: big.NewInt(1),
+ ConfigDigest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
+ Epoch: 0x519,
+ Round: 0x5,
+ Reimbursement: big.NewInt(0),
+ },
+ }
+
ocr2Reader := ocr2Mocks.NewOCR2Reader(t)
ocr2Reader.On(
"LatestRoundData",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
).Return(ocr2ClientLatestRoundDataResponse, nil).Once()
ocr2Reader.On(
"NewTransmissionsFromEventsAt",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
ocr2ClientLatestRoundDataResponse.BlockNumber,
).Return(ocr2ClientNewTransmissionEventAtResponse, nil).Once()
ocr2Reader.On(
"LatestConfigDetails",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
).Return(ocr2ClientLatestConfigDetailsResponse, nil).Once()
ocr2Reader.On(
"ConfigFromEventAt",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
ocr2ClientLatestConfigDetailsResponse.Block,
).Return(ocr2ClientConfigFromEventAtResponse, nil).Once()
ocr2Reader.On(
"LinkAvailableForPayment",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
).Return(ocr2ClientLinkAvailableForPaymentResponse, nil).Once()
baseReader := starknetMocks.NewReader(t)
ocr2Reader.On("BaseReader").Return(baseReader)
+
+ linkTokenAddressFelt, err := starknetutils.HexToFelt(chainConfig.GetLinkTokenAddress())
+ require.NoError(t, err)
+
+ accountBalanceFelt, err := starknetutils.HexToFelt("0x56bc75e2d63100000")
+ require.NoError(t, err)
+ starknetReaderCallContractBalanceOfResponse := []*felt.Felt{accountBalanceFelt, &felt.Zero}
+
baseReader.On(
"CallContract",
mock.Anything, // ctx
starknet.CallOps{
- ContractAddress: chainConfig.GetLinkTokenAddress(),
- Selector: "balanceOf",
- Calldata: []string{
- caigo.HexToBN(feedConfig.ContractAddress).String(),
- },
+ ContractAddress: linkTokenAddressFelt,
+ Selector: starknetutils.GetSelectorFromNameFelt("balance_of"),
+ Calldata: []*felt.Felt{feedContractAddressFelt},
},
).Return(starknetReaderCallContractBalanceOfResponse, nil)
@@ -79,6 +115,7 @@ func TestEnvelopeSource(t *testing.T) {
require.True(t, ok)
require.Equal(t, expectedEnvelope, envelope)
+
}
var (
@@ -89,28 +126,6 @@ var (
StartedAt: time.Date(2022, time.September, 27, 18, 50, 0, 0, time.Local),
UpdatedAt: time.Date(2022, time.September, 27, 18, 51, 0, 0, time.Local),
}
- ocr2ClientNewTransmissionEventAtResponse = []ocr2.NewTransmissionEvent{
- {
- RoundId: 0xf5b,
- LatestAnswer: bigIntFromString("-900000000"),
- Transmitter: caigotypes.StrToFelt("634447934223750826572902672583054702307815157196919304685470566142330202833"),
- LatestTimestamp: time.Date(2022, time.September, 27, 18, 51, 0, 0, time.Local),
- Observers: []uint8{0x1, 0x2, 0x3, 0x4},
- ObservationsLen: 0x4,
- Observations: []*big.Int{
- bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
- bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
- bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
- bigIntFromString("3618502788666131213697322783095070105623107215331596699973092056134972020481"),
- },
- JuelsPerFeeCoin: big.NewInt(451000),
- GasPrice: big.NewInt(1),
- ConfigDigest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
- Epoch: 0x519,
- Round: 0x5,
- Reimbursement: big.NewInt(0),
- },
- }
ocr2ClientLatestConfigDetailsResponse = ocr2.ContractConfigDetails{
Block: 0x11,
Digest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
@@ -120,11 +135,11 @@ var (
ConfigDigest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
ConfigCount: 0x1,
Signers: []types.OnchainPublicKey{
- types.OnchainPublicKey{0x6, 0x43, 0x41, 0xfa, 0xc3, 0x1, 0xc6, 0x2c, 0x38, 0xa9, 0xef, 0xdb, 0x86, 0xf6, 0xa2, 0x5a, 0x34, 0xd2, 0x4, 0x4f, 0x29, 0x2e, 0x94, 0xfb, 0xe4, 0x78, 0xa6, 0x67, 0x19, 0xb3, 0x80, 0x9e},
- types.OnchainPublicKey{0x1, 0xe2, 0xe1, 0x45, 0x47, 0x3, 0x7d, 0xb0, 0xd2, 0xe, 0xc6, 0xc9, 0x4b, 0xc7, 0x91, 0xea, 0xf2, 0xc9, 0x98, 0xad, 0x92, 0x79, 0xbb, 0xd, 0x21, 0x80, 0x15, 0x14, 0xd0, 0x6f, 0xa5, 0x7e},
- types.OnchainPublicKey{0x3, 0xb6, 0xcb, 0xd7, 0xbd, 0x52, 0x2d, 0xc8, 0xb0, 0xb4, 0x15, 0x3d, 0x60, 0x44, 0xec, 0xa7, 0x7e, 0x3e, 0xcf, 0xde, 0xe0, 0xc9, 0x5d, 0x20, 0x75, 0x50, 0x61, 0xf4, 0xbc, 0x7b, 0xf5, 0x4d},
- types.OnchainPublicKey{0x2, 0x4a, 0xa1, 0x21, 0x5b, 0xf4, 0xa3, 0xbb, 0x13, 0xea, 0x19, 0x57, 0x74, 0x28, 0xb7, 0xbe, 0xb5, 0xb9, 0x28, 0xb5, 0x74, 0x96, 0x78, 0xfa, 0x46, 0x87, 0x3b, 0x62, 0x7b, 0x22, 0x2a, 0x14},
- types.OnchainPublicKey{0x2, 0xa9, 0xc8, 0x4f, 0x88, 0x14, 0x17, 0xb5, 0xc9, 0xd1, 0x3b, 0x80, 0x2a, 0xc9, 0x93, 0xc5, 0x2c, 0x82, 0x88, 0x62, 0x32, 0xf7, 0x4e, 0x47, 0x5a, 0x92, 0xcc, 0x1a, 0xa, 0x1, 0x10, 0xda},
+ {0x6, 0x43, 0x41, 0xfa, 0xc3, 0x1, 0xc6, 0x2c, 0x38, 0xa9, 0xef, 0xdb, 0x86, 0xf6, 0xa2, 0x5a, 0x34, 0xd2, 0x4, 0x4f, 0x29, 0x2e, 0x94, 0xfb, 0xe4, 0x78, 0xa6, 0x67, 0x19, 0xb3, 0x80, 0x9e},
+ {0x1, 0xe2, 0xe1, 0x45, 0x47, 0x3, 0x7d, 0xb0, 0xd2, 0xe, 0xc6, 0xc9, 0x4b, 0xc7, 0x91, 0xea, 0xf2, 0xc9, 0x98, 0xad, 0x92, 0x79, 0xbb, 0xd, 0x21, 0x80, 0x15, 0x14, 0xd0, 0x6f, 0xa5, 0x7e},
+ {0x3, 0xb6, 0xcb, 0xd7, 0xbd, 0x52, 0x2d, 0xc8, 0xb0, 0xb4, 0x15, 0x3d, 0x60, 0x44, 0xec, 0xa7, 0x7e, 0x3e, 0xcf, 0xde, 0xe0, 0xc9, 0x5d, 0x20, 0x75, 0x50, 0x61, 0xf4, 0xbc, 0x7b, 0xf5, 0x4d},
+ {0x2, 0x4a, 0xa1, 0x21, 0x5b, 0xf4, 0xa3, 0xbb, 0x13, 0xea, 0x19, 0x57, 0x74, 0x28, 0xb7, 0xbe, 0xb5, 0xb9, 0x28, 0xb5, 0x74, 0x96, 0x78, 0xfa, 0x46, 0x87, 0x3b, 0x62, 0x7b, 0x22, 0x2a, 0x14},
+ {0x2, 0xa9, 0xc8, 0x4f, 0x88, 0x14, 0x17, 0xb5, 0xc9, 0xd1, 0x3b, 0x80, 0x2a, 0xc9, 0x93, 0xc5, 0x2c, 0x82, 0x88, 0x62, 0x32, 0xf7, 0x4e, 0x47, 0x5a, 0x92, 0xcc, 0x1a, 0xa, 0x1, 0x10, 0xda},
},
Transmitters: []types.Account{
"0x033c95af529827a2372743bfc820b4d0bd08605fda5e089d1a7ad3a33caa48fc",
@@ -140,9 +155,8 @@ var (
},
ConfigBlock: 0x11,
}
- starknetReaderCallContractBalanceOfResponse = []string{"0x56bc75e2d63100000", "0x0"}
- ocr2ClientLinkAvailableForPaymentResponse = bigIntFromString("99999991552000000000")
- expectedEnvelope = relayMonitoring.Envelope{
+ ocr2ClientLinkAvailableForPaymentResponse = bigIntFromString("99999991552000000000")
+ expectedEnvelope = relayMonitoring.Envelope{
ConfigDigest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
Epoch: 0x519,
Round: 0x5,
@@ -152,11 +166,11 @@ var (
ConfigDigest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
ConfigCount: 0x1,
Signers: []types.OnchainPublicKey{
- types.OnchainPublicKey{0x6, 0x43, 0x41, 0xfa, 0xc3, 0x1, 0xc6, 0x2c, 0x38, 0xa9, 0xef, 0xdb, 0x86, 0xf6, 0xa2, 0x5a, 0x34, 0xd2, 0x4, 0x4f, 0x29, 0x2e, 0x94, 0xfb, 0xe4, 0x78, 0xa6, 0x67, 0x19, 0xb3, 0x80, 0x9e},
- types.OnchainPublicKey{0x1, 0xe2, 0xe1, 0x45, 0x47, 0x3, 0x7d, 0xb0, 0xd2, 0xe, 0xc6, 0xc9, 0x4b, 0xc7, 0x91, 0xea, 0xf2, 0xc9, 0x98, 0xad, 0x92, 0x79, 0xbb, 0xd, 0x21, 0x80, 0x15, 0x14, 0xd0, 0x6f, 0xa5, 0x7e},
- types.OnchainPublicKey{0x3, 0xb6, 0xcb, 0xd7, 0xbd, 0x52, 0x2d, 0xc8, 0xb0, 0xb4, 0x15, 0x3d, 0x60, 0x44, 0xec, 0xa7, 0x7e, 0x3e, 0xcf, 0xde, 0xe0, 0xc9, 0x5d, 0x20, 0x75, 0x50, 0x61, 0xf4, 0xbc, 0x7b, 0xf5, 0x4d},
- types.OnchainPublicKey{0x2, 0x4a, 0xa1, 0x21, 0x5b, 0xf4, 0xa3, 0xbb, 0x13, 0xea, 0x19, 0x57, 0x74, 0x28, 0xb7, 0xbe, 0xb5, 0xb9, 0x28, 0xb5, 0x74, 0x96, 0x78, 0xfa, 0x46, 0x87, 0x3b, 0x62, 0x7b, 0x22, 0x2a, 0x14},
- types.OnchainPublicKey{0x2, 0xa9, 0xc8, 0x4f, 0x88, 0x14, 0x17, 0xb5, 0xc9, 0xd1, 0x3b, 0x80, 0x2a, 0xc9, 0x93, 0xc5, 0x2c, 0x82, 0x88, 0x62, 0x32, 0xf7, 0x4e, 0x47, 0x5a, 0x92, 0xcc, 0x1a, 0xa, 0x1, 0x10, 0xda},
+ {0x6, 0x43, 0x41, 0xfa, 0xc3, 0x1, 0xc6, 0x2c, 0x38, 0xa9, 0xef, 0xdb, 0x86, 0xf6, 0xa2, 0x5a, 0x34, 0xd2, 0x4, 0x4f, 0x29, 0x2e, 0x94, 0xfb, 0xe4, 0x78, 0xa6, 0x67, 0x19, 0xb3, 0x80, 0x9e},
+ {0x1, 0xe2, 0xe1, 0x45, 0x47, 0x3, 0x7d, 0xb0, 0xd2, 0xe, 0xc6, 0xc9, 0x4b, 0xc7, 0x91, 0xea, 0xf2, 0xc9, 0x98, 0xad, 0x92, 0x79, 0xbb, 0xd, 0x21, 0x80, 0x15, 0x14, 0xd0, 0x6f, 0xa5, 0x7e},
+ {0x3, 0xb6, 0xcb, 0xd7, 0xbd, 0x52, 0x2d, 0xc8, 0xb0, 0xb4, 0x15, 0x3d, 0x60, 0x44, 0xec, 0xa7, 0x7e, 0x3e, 0xcf, 0xde, 0xe0, 0xc9, 0x5d, 0x20, 0x75, 0x50, 0x61, 0xf4, 0xbc, 0x7b, 0xf5, 0x4d},
+ {0x2, 0x4a, 0xa1, 0x21, 0x5b, 0xf4, 0xa3, 0xbb, 0x13, 0xea, 0x19, 0x57, 0x74, 0x28, 0xb7, 0xbe, 0xb5, 0xb9, 0x28, 0xb5, 0x74, 0x96, 0x78, 0xfa, 0x46, 0x87, 0x3b, 0x62, 0x7b, 0x22, 0x2a, 0x14},
+ {0x2, 0xa9, 0xc8, 0x4f, 0x88, 0x14, 0x17, 0xb5, 0xc9, 0xd1, 0x3b, 0x80, 0x2a, 0xc9, 0x93, 0xc5, 0x2c, 0x82, 0x88, 0x62, 0x32, 0xf7, 0x4e, 0x47, 0x5a, 0x92, 0xcc, 0x1a, 0xa, 0x1, 0x10, 0xda},
},
Transmitters: []types.Account{
"0x033c95af529827a2372743bfc820b4d0bd08605fda5e089d1a7ad3a33caa48fc",
diff --git a/monitoring/pkg/monitoring/source_proxy.go b/monitoring/pkg/monitoring/source_proxy.go
index f1b1800..77bce1b 100644
--- a/monitoring/pkg/monitoring/source_proxy.go
+++ b/monitoring/pkg/monitoring/source_proxy.go
@@ -5,7 +5,10 @@ import (
"fmt"
"math/big"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
)
@@ -30,8 +33,16 @@ func (s *proxySourceFactory) NewSource(
_ relayMonitoring.ChainConfig,
feedConfig relayMonitoring.FeedConfig,
) (relayMonitoring.Source, error) {
+ starknetFeedConfig, ok := feedConfig.(StarknetFeedConfig)
+ if !ok {
+ return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", feedConfig)
+ }
+ contractAddress, err := starknetutils.HexToFelt(starknetFeedConfig.ProxyAddress)
+ if err != nil {
+ return nil, err
+ }
return &proxySource{
- feedConfig.GetContractAddress(),
+ contractAddress,
s.ocr2Reader,
}, nil
}
@@ -41,16 +52,16 @@ func (s *proxySourceFactory) GetType() string {
}
type proxySource struct {
- contractAddress string
+ contractAddress *felt.Felt
ocr2Reader ocr2.OCR2Reader
}
func (s *proxySource) Fetch(ctx context.Context) (interface{}, error) {
- latestTransmission, err := s.ocr2Reader.LatestTransmissionDetails(ctx, s.contractAddress)
+ latestRoundData, err := s.ocr2Reader.LatestRoundData(ctx, s.contractAddress)
if err != nil {
- return nil, fmt.Errorf("couldn't fetch latest_transmission_details: %w", err)
+ return nil, fmt.Errorf("couldn't fetch latest_round_data: %w", err)
}
return ProxyData{
- Answer: latestTransmission.LatestAnswer,
+ Answer: latestRoundData.Answer,
}, nil
}
diff --git a/monitoring/pkg/monitoring/source_proxy_test.go b/monitoring/pkg/monitoring/source_proxy_test.go
index 7705657..faf6c7b 100644
--- a/monitoring/pkg/monitoring/source_proxy_test.go
+++ b/monitoring/pkg/monitoring/source_proxy_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- "github.com/goplugin/plugin-libocr/offchainreporting2/types"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@@ -21,12 +21,15 @@ func TestProxySource(t *testing.T) {
chainConfig := generateChainConfig()
feedConfig := generateFeedConfig()
+ proxyContractAddressFelt, err := starknetutils.HexToFelt(feedConfig.ProxyAddress)
+ require.NoError(t, err)
+
ocr2Reader := ocr2Mocks.NewOCR2Reader(t)
ocr2Reader.On(
- "LatestTransmissionDetails",
+ "LatestRoundData",
mock.Anything, // ctx
- feedConfig.ContractAddress,
- ).Return(ocr2ClientLatestTransmissionDetailsResponseForProxy, nil).Once()
+ proxyContractAddressFelt,
+ ).Return(ocr2ClientLatestRoundDataResponseForProxy, nil).Once()
factory := NewProxySourceFactory(ocr2Reader)
source, err := factory.NewSource(chainConfig, feedConfig)
@@ -37,17 +40,17 @@ func TestProxySource(t *testing.T) {
require.True(t, ok)
require.Equal(t,
- ocr2ClientLatestTransmissionDetailsResponseForProxy.LatestAnswer.String(),
+ ocr2ClientLatestRoundDataResponseForProxy.Answer.String(),
proxyData.Answer.String(),
)
}
var (
- ocr2ClientLatestTransmissionDetailsResponseForProxy = ocr2.TransmissionDetails{
- Digest: types.ConfigDigest{0x0, 0x4, 0x18, 0xe5, 0x44, 0xab, 0xa8, 0x18, 0x15, 0xa5, 0x2b, 0xf0, 0x11, 0x58, 0xc6, 0x9b, 0x38, 0x8a, 0x48, 0x9f, 0x76, 0xd, 0xd8, 0x3d, 0x84, 0x3f, 0x1d, 0x31, 0x22, 0xdb, 0x78, 0xa},
- Epoch: 0x1,
- Round: 0x9,
- LatestAnswer: big.NewInt(10000),
- LatestTimestamp: time.Now(),
+ ocr2ClientLatestRoundDataResponseForProxy = ocr2.RoundData{
+ RoundID: 9,
+ Answer: big.NewInt(10000),
+ BlockNumber: 777,
+ StartedAt: time.Now(),
+ UpdatedAt: time.Now(),
}
)
diff --git a/monitoring/pkg/monitoring/source_transmission_details.go b/monitoring/pkg/monitoring/source_transmission_details.go
new file mode 100644
index 0000000..9f801ba
--- /dev/null
+++ b/monitoring/pkg/monitoring/source_transmission_details.go
@@ -0,0 +1,82 @@
+package monitoring
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
+)
+
+type TransmissionInfo struct {
+ GasPrice *big.Int
+ ObservationLength uint32
+}
+
+type TransmissionsEnvelope struct {
+ Transmissions []TransmissionInfo
+}
+
+func NewTransmissionDetailsSourceFactory(
+ ocr2Reader ocr2.OCR2Reader,
+) relayMonitoring.SourceFactory {
+ return &transmissionDetailsSourceFactory{
+ ocr2Reader,
+ }
+}
+
+type transmissionDetailsSourceFactory struct {
+ ocr2Reader ocr2.OCR2Reader
+}
+
+func (s *transmissionDetailsSourceFactory) NewSource(
+ _ relayMonitoring.ChainConfig,
+ feedConfig relayMonitoring.FeedConfig,
+) (relayMonitoring.Source, error) {
+ starknetFeedConfig, ok := feedConfig.(StarknetFeedConfig)
+ if !ok {
+ return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", feedConfig)
+ }
+ contractAddress, err := starknetutils.HexToFelt(starknetFeedConfig.ContractAddress)
+ if err != nil {
+ return nil, err
+ }
+ return &transmissionDetailsSource{
+ contractAddress,
+ s.ocr2Reader,
+ }, nil
+}
+
+func (s *transmissionDetailsSourceFactory) GetType() string {
+ return "transmission details"
+}
+
+type transmissionDetailsSource struct {
+ contractAddress *felt.Felt
+ ocr2Reader ocr2.OCR2Reader
+}
+
+func (s *transmissionDetailsSource) Fetch(ctx context.Context) (interface{}, error) {
+ latestRound, err := s.ocr2Reader.LatestRoundData(ctx, s.contractAddress)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch latest_round_data: %w", err)
+ }
+ transmissions, err := s.ocr2Reader.NewTransmissionsFromEventsAt(ctx, s.contractAddress, latestRound.BlockNumber)
+ if err != nil {
+ return nil, fmt.Errorf("couldn't fetch transmission events: %w", err)
+ }
+ var envelope TransmissionsEnvelope
+ for _, t := range transmissions {
+ envelope.Transmissions = append(
+ envelope.Transmissions,
+ TransmissionInfo{GasPrice: t.GasPrice, ObservationLength: t.ObservationsLen},
+ )
+ }
+
+ return envelope, nil
+}
diff --git a/monitoring/pkg/monitoring/source_transmission_details_test.go b/monitoring/pkg/monitoring/source_transmission_details_test.go
new file mode 100644
index 0000000..dd6713c
--- /dev/null
+++ b/monitoring/pkg/monitoring/source_transmission_details_test.go
@@ -0,0 +1,57 @@
+package monitoring
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ ocr2Mocks "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2/mocks"
+)
+
+func TestTransmissionDetailsSource(t *testing.T) {
+ chainConfig := generateChainConfig()
+ feedConfig := generateFeedConfig()
+
+ contractAddressFelt, err := starknetutils.HexToFelt(feedConfig.ContractAddress)
+ require.NoError(t, err)
+
+ ocr2Reader := ocr2Mocks.NewOCR2Reader(t)
+ blockNumber := uint64(777)
+ ocr2Reader.On(
+ "LatestRoundData",
+ mock.Anything, // ctx
+ contractAddressFelt,
+ ).Return(ocr2.RoundData{BlockNumber: blockNumber}, nil).Once()
+ ocr2Reader.On(
+ "NewTransmissionsFromEventsAt",
+ mock.Anything, // ctx
+ contractAddressFelt,
+ blockNumber,
+ ).Return(
+ []ocr2.NewTransmissionEvent{
+ {
+ GasPrice: new(big.Int).SetUint64(7),
+ ObservationsLen: 7,
+ },
+ },
+ nil,
+ ).Once()
+
+ factory := NewTransmissionDetailsSourceFactory(ocr2Reader)
+ source, err := factory.NewSource(chainConfig, feedConfig)
+ require.NoError(t, err)
+
+ transmissionsEnvelope, err := source.Fetch(context.Background())
+ require.NoError(t, err)
+ envelope, ok := transmissionsEnvelope.(TransmissionsEnvelope)
+ require.True(t, ok)
+
+ require.Equal(t, len(envelope.Transmissions), 1)
+ require.Equal(t, envelope.Transmissions[0].GasPrice.Uint64(), uint64(7))
+ require.Equal(t, envelope.Transmissions[0].ObservationLength, uint32(7))
+}
diff --git a/monitoring/pkg/monitoring/source_txresults.go b/monitoring/pkg/monitoring/source_txresults.go
index 04592df..8ff7764 100644
--- a/monitoring/pkg/monitoring/source_txresults.go
+++ b/monitoring/pkg/monitoring/source_txresults.go
@@ -5,7 +5,10 @@ import (
"fmt"
"sync"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
+ "github.com/NethermindEth/juno/core/felt"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
)
@@ -26,8 +29,12 @@ func (s *txResultsSourceFactory) NewSource(
_ relayMonitoring.ChainConfig,
feedConfig relayMonitoring.FeedConfig,
) (relayMonitoring.Source, error) {
+ contractAddress, err := starknetutils.HexToFelt(feedConfig.GetContractAddress())
+ if err != nil {
+ return nil, err
+ }
return &txResultsSource{
- feedConfig.GetContractAddress(),
+ contractAddress,
s.ocr2Reader,
0,
sync.Mutex{},
@@ -39,7 +46,7 @@ func (s *txResultsSourceFactory) GetType() string {
}
type txResultsSource struct {
- contractAddress string
+ contractAddress *felt.Felt
ocr2Reader ocr2.OCR2Reader
prevRoundID uint32
diff --git a/monitoring/pkg/monitoring/source_txresults_test.go b/monitoring/pkg/monitoring/source_txresults_test.go
index 7c6a0bb..ad277c5 100644
--- a/monitoring/pkg/monitoring/source_txresults_test.go
+++ b/monitoring/pkg/monitoring/source_txresults_test.go
@@ -4,10 +4,12 @@ import (
"context"
"testing"
- relayMonitoring "github.com/goplugin/plugin-relay/pkg/monitoring"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
+ starknetutils "github.com/NethermindEth/starknet.go/utils"
+ relayMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
+
"github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
ocr2Mocks "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2/mocks"
)
@@ -19,16 +21,19 @@ func TestTxResultsSource(t *testing.T) {
chainConfig := generateChainConfig()
feedConfig := generateFeedConfig()
+ feedContractAddressFelt, err := starknetutils.HexToFelt(feedConfig.ContractAddress)
+ require.NoError(t, err)
+
ocr2Reader := ocr2Mocks.NewOCR2Reader(t)
ocr2Reader.On(
"LatestRoundData",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
).Return(ocr2ClientLatestRoundDataResponseForTxResults1, nil).Once()
ocr2Reader.On(
"LatestRoundData",
mock.Anything, // ctx
- feedConfig.ContractAddress,
+ feedContractAddressFelt,
).Return(ocr2ClientLatestRoundDataResponseForTxResults2, nil).Once()
factory := NewTxResultsSourceFactory(ocr2Reader)
diff --git a/monitoring/pkg/monitoring/testutils.go b/monitoring/pkg/monitoring/testutils.go
index 40d2a92..4d123a0 100644
--- a/monitoring/pkg/monitoring/testutils.go
+++ b/monitoring/pkg/monitoring/testutils.go
@@ -5,8 +5,29 @@ import (
"math/big"
"math/rand"
"time"
+
+ commonMonitoring "github.com/goplugin/plugin-common/pkg/monitoring"
)
+func generateNodeConfig() []commonMonitoring.NodeConfig {
+ starknetNodes := []StarknetNodeConfig{
+ {
+ ID: "node-0",
+ NodeAddress: []string{generateAddr()},
+ },
+ {
+ ID: "node-1",
+ NodeAddress: []string{generateAddr()},
+ },
+ }
+
+ nodes := make([]commonMonitoring.NodeConfig, len(starknetNodes))
+ for i, starknetNode := range starknetNodes {
+ nodes[i] = starknetNode
+ }
+ return nodes
+}
+
func generateChainConfig() StarknetConfig {
return StarknetConfig{
rpcEndpoint: "http://starknet/6969",
diff --git a/ops/charts/devnet/templates/deployment.yaml b/ops/charts/devnet/templates/deployment.yaml
index 10735f7..f3c841b 100644
--- a/ops/charts/devnet/templates/deployment.yaml
+++ b/ops/charts/devnet/templates/deployment.yaml
@@ -29,8 +29,8 @@ spec:
{{- if eq .Values.real_node true }}
image: "{{ .Values.repository | default "eqlabs/pathfinder"}}:{{ .Values.tag | default "v0.1.8-alpha"}}"
{{- else }}
- image: "{{ .Values.repository | default "shardlabs/starknet-devnet"}}:{{ .Values.tag | default "0.5.0"}}"
- args: ["--lite-mode", "--port", {{ .Values.service.internalPort | quote}}, "--seed", {{ .Values.seed | quote}}]
+ image: "{{ .Values.repository | default "shardlabs/starknet-devnet-rs"}}:{{ .Values.tag | default "a147b4cd72f9ce9d1fa665d871231370db0f51c7"}}"
+ args: ["--port", {{ .Values.service.internalPort | quote}}, "--seed", {{ .Values.seed | quote}}, "--account-class", "cairo1", "--gas-price", "1", "--data-gas-price", "1"]
{{- end }}
imagePullPolicy: IfNotPresent
{{- if eq .Values.real_node true }}
@@ -55,14 +55,18 @@ spec:
httpGet:
path: /is_alive
port: {{ .Values.service.externalPort }}
- initialDelaySeconds: 1
+ initialDelaySeconds: 5
periodSeconds: 30
+ timeoutSeconds: 300
+ failureThreshold: 10
readinessProbe:
httpGet:
path: /is_alive
port: {{ .Values.service.externalPort }}
- initialDelaySeconds: 2
- periodSeconds: 1
+ initialDelaySeconds: 5
+ periodSeconds: 30
+ timeoutSeconds: 300
+ failureThreshold: 10
resources:
requests:
memory: {{ .Values.resources.requests.memory }}
diff --git a/ops/devnet/devnet.go b/ops/devnet/devnet.go
deleted file mode 100644
index 1830402..0000000
--- a/ops/devnet/devnet.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package devnet
-
-import (
- "context"
- "fmt"
- "strings"
- "time"
-
- caigotypes "github.com/dontpanicdao/caigo/types"
- "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/ocr2"
-
- "github.com/go-resty/resty/v2"
- "github.com/rs/zerolog/log"
-)
-
-type StarknetDevnetClient struct {
- ctx context.Context
- cancel context.CancelFunc
- client *resty.Client
- dumpPath string
-}
-
-func (devnet *StarknetDevnetClient) NewStarknetDevnetClient(rpcUrl string, dumpPath string) *StarknetDevnetClient {
- ctx, cancel := context.WithCancel(context.Background())
- return &StarknetDevnetClient{
- ctx: ctx,
- cancel: cancel,
- client: resty.New().SetBaseURL(rpcUrl),
- dumpPath: dumpPath,
- }
-}
-
-// AutoSyncL1 auto calls /flush/ every 2 seconds to sync L1<>L2
-func (devnet *StarknetDevnetClient) AutoSyncL1() {
- t := time.NewTicker(2 * time.Second)
- go func() {
- for {
- select {
- case <-devnet.ctx.Done():
- log.Debug().Msg("Shutting down L1 sync")
- return
- case <-t.C:
- log.Debug().Msg("Syncing L1")
- _, err := devnet.client.R().Post("/postman/flush")
- if err != nil {
- log.Error().Err(err).Msg("failed to sync L1")
- }
- }
- }
- }()
-}
-
-// AutoDumpState dumps devnet state every 10 sec
-func (devnet *StarknetDevnetClient) AutoDumpState() {
- t := time.NewTicker(20 * time.Minute)
- go func() {
- for {
- select {
- case <-devnet.ctx.Done():
- log.Debug().Msg("Shutting down devnet dump")
- return
- case <-t.C:
- log.Debug().Msg("Dumping state")
- _, err := devnet.client.R().SetBody(map[string]any{
- "path": devnet.dumpPath,
- }).Post("/dump")
- if err != nil {
- log.Error().Err(err).Msg("Failed to dump devnet state")
- }
- }
- }
- }()
-}
-
-// AutoLoadState auto loads last saved devnet state on contract not found
-func (devnet *StarknetDevnetClient) AutoLoadState(client *ocr2.Client, ocrAddress string) {
- t := time.NewTicker(15 * time.Second)
- go func() {
- for {
- select {
- case <-devnet.ctx.Done():
- log.Debug().Msg("Shutting down devnet dump")
- return
- case <-t.C:
- log.Debug().Msg("Checking for devnet OCR contract errors")
- _, err := client.LatestTransmissionDetails(devnet.ctx, caigotypes.HexToHash(ocrAddress))
- if err != nil && strings.Contains(err.Error(), "is not deployed") {
- _, err = devnet.client.R().SetBody(map[string]any{
- "path": devnet.dumpPath,
- }).Post("/load")
- if err != nil {
- log.Error().Err(err).Msg("Failed to dump devnet state")
- }
- }
-
- }
- }
- }()
-}
-
-// FundAccounts Funds provided accounts with 100 eth each
-func (devnet *StarknetDevnetClient) FundAccounts(l2AccList []string) error {
- for _, key := range l2AccList {
- res, err := devnet.client.R().SetBody(map[string]any{
- "address": key,
- "amount": 1e21,
- }).Post("/mint")
- if err != nil {
- return err
- }
- log.Info().Msg(fmt.Sprintf("Funding account: %s", string(res.Body())))
- }
- return nil
-}
-
-// LoadL1MessagingContract loads and sets up the L1 messaging contract and URL
-func (devnet *StarknetDevnetClient) LoadL1MessagingContract(l1RpcUrl string) error {
- resp, err := devnet.client.R().SetBody(map[string]any{
- "networkUrl": l1RpcUrl,
- }).Post("/postman/load_l1_messaging_contract")
- if err != nil {
- return err
- }
- log.Warn().Interface("Response", resp.String()).Msg("Set up L1 messaging contract")
- return nil
-}
diff --git a/ops/devnet/environment.go b/ops/devnet/environment.go
index dc5e38f..0f53c8d 100644
--- a/ops/devnet/environment.go
+++ b/ops/devnet/environment.go
@@ -4,9 +4,11 @@ import (
"fmt"
"github.com/rs/zerolog/log"
- "github.com/goplugin/plugin-env/client"
- "github.com/goplugin/plugin-env/config"
- "github.com/goplugin/plugin-env/environment"
+
+ "github.com/goplugin/plugin-testing-framework/k8s/client"
+ "github.com/goplugin/plugin-testing-framework/k8s/config"
+ "github.com/goplugin/plugin-testing-framework/k8s/environment"
+
"github.com/goplugin/plugin-starknet/ops/utils"
)
@@ -51,17 +53,17 @@ func (m Chart) GetVersion() string {
}
func (m Chart) ExportData(e *environment.Environment) error {
- devnetLocalHttp, err := e.Fwd.FindPort("starknet-dev:0", "starknetdev", "http").As(client.LocalConnection, client.HTTP)
+ devnetLocalHTTP, err := e.Fwd.FindPort("starknet-dev:0", "starknetdev", "http").As(client.LocalConnection, client.HTTP)
if err != nil {
return err
}
- devnetInternalHttp, err := e.Fwd.FindPort("starknet-dev:0", "starknetdev", "http").As(client.RemoteConnection, client.HTTP)
+ devnetInternalHTTP, err := e.Fwd.FindPort("starknet-dev:0", "starknetdev", "http").As(client.RemoteConnection, client.HTTP)
if err != nil {
return err
}
- e.URLs[NetworkName] = append(e.URLs[NetworkName], devnetLocalHttp)
- e.URLs[NetworkName] = append(e.URLs[NetworkName], devnetInternalHttp)
- log.Info().Str("Name", "Devnet").Str("URLs", devnetLocalHttp).Msg("Devnet network")
+ e.URLs[NetworkName] = append(e.URLs[NetworkName], devnetLocalHTTP)
+ e.URLs[NetworkName] = append(e.URLs[NetworkName], devnetInternalHTTP)
+ log.Info().Str("Name", "Devnet").Str("URLs", devnetLocalHTTP).Msg("Devnet network")
return nil
}
@@ -70,8 +72,8 @@ func defaultProps() map[string]any {
"replicas": "1",
"starknet-dev": map[string]any{
"image": map[string]any{
- "image": "shardlabs/starknet-devnet",
- "version": "v0.3.5",
+ "image": "shardlabs/starknet-devnet-rs",
+ "version": "a147b4cd72f9ce9d1fa665d871231370db0f51c7",
},
"resources": map[string]any{
"requests": map[string]any{
@@ -87,7 +89,6 @@ func defaultProps() map[string]any {
"real_node": "false",
},
}
-
}
func New(props *Props) environment.ConnectedChart {
diff --git a/ops/gauntlet/gauntlet_starknet.go b/ops/gauntlet/gauntlet_starknet.go
index 17108e0..fa04b8f 100644
--- a/ops/gauntlet/gauntlet_starknet.go
+++ b/ops/gauntlet/gauntlet_starknet.go
@@ -20,7 +20,7 @@ type StarknetGauntlet struct {
}
// GauntletResponse Default response output for starknet gauntlet commands
-type GauntletResponse struct {
+type GauntletResponse struct { //nolint:revive
Responses []struct {
Tx struct {
Hash string `json:"hash"`
@@ -57,8 +57,8 @@ func NewStarknetGauntlet(workingDir string) (*StarknetGauntlet, error) {
return sg, nil
}
-// FetchGauntletJsonOutput Parse gauntlet json response that is generated after yarn gauntlet command execution
-func (sg *StarknetGauntlet) FetchGauntletJsonOutput() (*GauntletResponse, error) {
+// FetchGauntletJSONOutput Parse gauntlet json response that is generated after yarn gauntlet command execution
+func (sg *StarknetGauntlet) FetchGauntletJSONOutput() (*GauntletResponse, error) {
var payload = &GauntletResponse{}
gauntletOutput, err := os.ReadFile(sg.dir + "report.json")
if err != nil {
@@ -72,8 +72,10 @@ func (sg *StarknetGauntlet) FetchGauntletJsonOutput() (*GauntletResponse, error)
}
// SetupNetwork Sets up a new network and sets the NODE_URL for Devnet / Starknet RPC
-func (sg *StarknetGauntlet) SetupNetwork(addr string) error {
+func (sg *StarknetGauntlet) SetupNetwork(addr string, account string, privateKey string) error {
sg.G.AddNetworkConfigVar("NODE_URL", addr)
+ sg.G.AddNetworkConfigVar("ACCOUNT", account)
+ sg.G.AddNetworkConfigVar("PRIVATE_KEY", privateKey)
err := sg.G.WriteNetworkConfigMap(sg.dir + "packages-ts/starknet-gauntlet-cli/networks/")
if err != nil {
return err
@@ -97,7 +99,7 @@ func (sg *StarknetGauntlet) DeployAccountContract(salt int64, pubKey string) (st
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -109,7 +111,7 @@ func (sg *StarknetGauntlet) DeployLinkTokenContract() (string, error) {
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -121,7 +123,7 @@ func (sg *StarknetGauntlet) MintLinkToken(token, to, amount string) (string, err
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -133,7 +135,7 @@ func (sg *StarknetGauntlet) TransferToken(token, to, amount string) (string, err
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -145,7 +147,7 @@ func (sg *StarknetGauntlet) DeployOCR2ControllerContract(minSubmissionValue int6
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -157,7 +159,7 @@ func (sg *StarknetGauntlet) DeployAccessControllerContract() (string, error) {
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -169,7 +171,7 @@ func (sg *StarknetGauntlet) DeployOCR2ProxyContract(aggregator string) (string,
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -181,7 +183,7 @@ func (sg *StarknetGauntlet) SetOCRBilling(observationPaymentGjuels int64, transm
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -193,7 +195,7 @@ func (sg *StarknetGauntlet) SetConfigDetails(cfg string, ocrAddress string) (str
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
@@ -205,7 +207,7 @@ func (sg *StarknetGauntlet) AddAccess(aggregator, address string) (string, error
if err != nil {
return "", err
}
- sg.gr, err = sg.FetchGauntletJsonOutput()
+ sg.gr, err = sg.FetchGauntletJSONOutput()
if err != nil {
return "", err
}
diff --git a/ops/go.mod b/ops/go.mod
index 68a54f9..3308542 100644
--- a/ops/go.mod
+++ b/ops/go.mod
@@ -1,38 +1,41 @@
module github.com/goplugin/plugin-starknet/ops
-go 1.20
+go 1.21.3
+
+toolchain go1.21.5
require (
- github.com/dontpanicdao/caigo v0.4.0
- github.com/go-resty/resty/v2 v2.7.0
- github.com/rs/zerolog v1.29.1
- github.com/goplugin/plugin-env v0.3.29
- github.com/goplugin/plugin-starknet/relayer v0.0.0-20221102160912-61646f534e3a
- github.com/goplugin/plugin-testing-framework v1.11.5
+ github.com/rs/zerolog v1.30.0
+ github.com/goplugin/plugin-env v0.0.1 //plugin update changes
+ //github.com/goplugin/plugin-env v0.3.29
+ github.com/goplugin/plugin-testing-framework v0.0.1 //plugin update changes
+ //github.com/goplugin/plugin-testing-framework v1.19.1
)
require (
- github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
+ dario.cat/mergo v1.0.0 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
- github.com/Masterminds/semver/v3 v3.2.0 // indirect
- github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect
github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect
github.com/aws/jsii-runtime-go v1.75.0 // indirect
- github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/deckarep/golang-set/v2 v2.1.0 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
+ github.com/containerd/containerd v1.7.3 // indirect
+ github.com/cpuguy83/dockercfg v0.3.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/docker/distribution v2.8.2+incompatible // indirect
+ github.com/docker/docker v24.0.5+incompatible // indirect
+ github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
- github.com/emicklei/go-restful/v3 v3.9.0 // indirect
- github.com/ethereum/go-ethereum v1.11.5 // indirect
+ github.com/emicklei/go-restful/v3 v3.10.2 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
@@ -40,110 +43,111 @@ require (
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/go-errors/errors v1.4.2 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
- github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/go-openapi/jsonpointer v0.19.6 // indirect
+ github.com/go-logr/logr v1.3.0 // indirect
+ github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
- github.com/go-stack/stack v1.8.1 // indirect
+ github.com/go-openapi/swag v0.22.4 // indirect
+ github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic v0.6.9 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
- github.com/google/go-querystring v1.1.0 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/google/uuid v1.3.0 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
+ github.com/google/uuid v1.4.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
- github.com/holiman/uint256 v1.2.0 // indirect
- github.com/imdario/mergo v0.3.13 // indirect
- github.com/inconshreveable/mousetrap v1.0.1 // indirect
+ github.com/imdario/mergo v0.3.16 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
- github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.17.2 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.17 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+ github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
- github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
+ github.com/moby/sys/sequential v0.5.0 // indirect
+ github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
- github.com/mr-tron/base58 v1.2.0 // indirect
+ github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/onsi/ginkgo/v2 v2.9.7 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
+ github.com/opencontainers/runc v1.1.7 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_golang v1.15.0 // indirect
- github.com/prometheus/client_model v0.3.0 // indirect
- github.com/prometheus/common v0.42.0 // indirect
- github.com/prometheus/procfs v0.9.0 // indirect
+ github.com/prometheus/client_golang v1.17.0 // indirect
+ github.com/prometheus/client_model v0.5.0 // indirect
+ github.com/prometheus/common v0.45.0 // indirect
+ github.com/prometheus/procfs v0.12.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/russross/blackfriday v1.6.0 // indirect
- github.com/satori/go.uuid v1.2.0 // indirect
- github.com/shirou/gopsutil v3.21.11+incompatible // indirect
- github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82 // indirect
- github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc // indirect
- github.com/spf13/cobra v1.6.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
- github.com/stretchr/testify v1.8.2 // indirect
- github.com/tklauser/go-sysconf v0.3.10 // indirect
- github.com/tklauser/numcpus v0.5.0 // indirect
+ github.com/stretchr/testify v1.8.4 // indirect
+ github.com/testcontainers/testcontainers-go v0.23.0 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
github.com/yuin/goldmark v1.4.13 // indirect
- github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect
- go.uber.org/atomic v1.10.0 // indirect
- go.uber.org/multierr v1.9.0 // indirect
- go.uber.org/zap v1.24.0 // indirect
- golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
+ go.uber.org/goleak v1.3.0 // indirect
+ golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
- golang.org/x/mod v0.9.0 // indirect
- golang.org/x/net v0.9.0 // indirect
- golang.org/x/oauth2 v0.6.0 // indirect
- golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.7.0 // indirect
- golang.org/x/term v0.7.0 // indirect
- golang.org/x/text v0.9.0 // indirect
+ golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/oauth2 v0.15.0 // indirect
+ golang.org/x/sync v0.6.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/term v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.7.0 // indirect
+ golang.org/x/tools v0.16.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/protobuf v1.30.0 // indirect
+ google.golang.org/appengine v1.6.8 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
+ google.golang.org/grpc v1.59.0 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.25.4 // indirect
+ k8s.io/api v0.27.3 // indirect
k8s.io/apiextensions-apiserver v0.25.3 // indirect
- k8s.io/apimachinery v0.25.4 // indirect
- k8s.io/cli-runtime v0.25.4 // indirect
- k8s.io/client-go v0.25.4 // indirect
- k8s.io/component-base v0.25.4 // indirect
- k8s.io/klog/v2 v2.80.1 // indirect
- k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
- k8s.io/kubectl v0.25.4 // indirect
- k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
+ k8s.io/apimachinery v0.27.3 // indirect
+ k8s.io/cli-runtime v0.25.11 // indirect
+ k8s.io/client-go v0.27.3 // indirect
+ k8s.io/component-base v0.26.2 // indirect
+ k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 // indirect
+ k8s.io/kubectl v0.25.11 // indirect
+ k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect
sigs.k8s.io/controller-runtime v0.13.0 // indirect
- sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
replace (
- // Fix go mod tidy issue for ambiguous imports from go-ethereum
- // See https://github.com/ugorji/go/issues/279
- github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
+ // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69
+ github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.1.1 //plugin update changes
+ //github.com/mwitkow/grpc-proxy => github.com/goplugin/grpc-proxy v0.0.0-20230731113816-f1be6620749f
+
github.com/goplugin/plugin-starknet/relayer => ../relayer
+
+ // K8s imports are weird
+ k8s.io/api => k8s.io/api v0.25.4
+ k8s.io/client-go => k8s.io/client-go v0.25.4
)
diff --git a/ops/go.sum b/ops/go.sum
index d3518a9..b7e704a 100644
--- a/ops/go.sum
+++ b/ops/go.sum
@@ -1,41 +1,42 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
-github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
-github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
-github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac h1:TQ2m26VW06Df1P82Ed/jZhBtf13pReWyl2XQ8hy+J08=
-github.com/NethermindEth/juno v0.0.0-20220630151419-cbd368b222ac/go.mod h1:FTk2+xybtQe5X+oNFx+a0n5EeZMD9Nc+LCH4fxFwrEE=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+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/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek=
+github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g=
github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI=
github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4=
github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I=
-github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
-github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
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/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
-github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E=
-github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8=
-github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA=
+github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM=
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 h1:rvc39Ol6z3MvaBzXkxFC6Nfsnixq/dRypushKDd7Nc0=
github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5/go.mod h1:R/pdNYDYFQk+tuuOo7QES1kkv6OLmp5ze2XBZQIVffM=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
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/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -50,40 +51,38 @@ 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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
-github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
-github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk=
-github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
+github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o=
+github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
+github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
-github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
+github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
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/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/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
+github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
+github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dontpanicdao/caigo v0.4.0 h1:S0wRKh2EZ9qj6IfHZIGXxiJF37emRCqnZwDhRb1+DJ4=
-github.com/dontpanicdao/caigo v0.4.0/go.mod h1:1YuwgcVLODaS/n0vfuYN/Q0mdWs8UDfDMkSpUdkKXD4=
-github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
-github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
-github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
-github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE=
+github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ=
-github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -98,35 +97,32 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
-github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
-github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
+github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
-github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
-github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
+github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
-github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
-github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
@@ -142,7 +138,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
@@ -153,56 +148,50 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
-github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA=
+github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
+github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-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/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
-github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
-github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
-github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
-github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
-github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
-github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
+github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
-github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
+github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
+github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
@@ -210,17 +199,20 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
-github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
+github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
+github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -228,16 +220,24 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
-github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
-github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
-github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
-github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
+github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
+github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
+github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
+github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
+github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
+github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -246,48 +246,41 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
-github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
+github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
-github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
-github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
-github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4=
github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
-github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
-github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
+github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
-github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
-github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/goplugin/plugin-env v0.3.29 h1:hcIw/BeuB0wKiiE3umAUNBZzWkHO24XF3OW9xSrlMbI=
github.com/goplugin/plugin-env v0.3.29/go.mod h1:9c0Czq4a6wZKY20BcoAlK29DnejQIiLo/MwKYtSFnHk=
-github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82 h1:FX7LW/czuotFwzfK3UavL7HkKQv6fn/5wzcZASdKWQ0=
-github.com/goplugin/plugin-relay v0.1.7-0.20230422214339-5fee8d7f3f82/go.mod h1:3E3PXaMEl2gADk/DTkbOxsvtpDcJ5ZSyW+vt0TjsEH0=
-github.com/goplugin/plugin-testing-framework v1.11.5 h1:gYSnOQhLxgE0mxwnv015nNnPgH9kcosx+AzPboEFo38=
-github.com/goplugin/plugin-testing-framework v1.11.5/go.mod h1:0ktPcDE5fFSvNewsaHuC4tGVaiCMQsl5RN/cWO5k0rg=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc h1:aSCDAai0Dmbhp/KHTtJnC/EJcaEz4CAO80SKRzRZiQA=
-github.com/goplugin/plugin-libocr v0.0.0-20230413082317-9561d14087cc/go.mod h1:5JnCHuYgmIP9ZyXzgAfI5Iwu0WxBtBKp+ApeT5o1Cjw=
+github.com/goplugin/plugin-testing-framework v1.19.1 h1:MdGM5jIrBi858Cv7qzfl1Qon93YW8InohAlDQqFoIb4=
+github.com/goplugin/plugin-testing-framework v1.19.1/go.mod h1:zScXRqmvbyTFUooyLYrOp4+V/sFPUbFJNRc72YmnuIk=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
-github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
+github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
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/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
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=
@@ -301,15 +294,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
-github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
-github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
-github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
-github.com/tklauser/numcpus v0.5.0 h1:ooe7gN0fg6myJ0EKoTAf5hebTZrH52px3New/D9iJ+A=
-github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKoflh+RQjo=
-github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/testcontainers/testcontainers-go v0.23.0 h1:ERYTSikX01QczBLPZpqsETTBO7lInqEP349phDOVJVs=
+github.com/testcontainers/testcontainers-go v0.23.0/go.mod h1:3gzuZfb7T9qfcH2pHpV4RLlWrPjeWNQah6XlYQ32c4I=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
@@ -319,26 +307,22 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
-github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.starlark.net v0.0.0-20220817180228-f738f5508c12 h1:xOBJXWGEDwU5xSDxH6macxO11Us0AH2fTa9rmsbbF7g=
go.starlark.net v0.0.0-20220817180228-f738f5508c12/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk=
-go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
-go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
-go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
-go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
-go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
-go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
+go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
-golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
+golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -347,66 +331,74 @@ golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPI
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
-golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
-golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
-golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
+golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ=
+golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
-golang.org/x/sync v0.1.0/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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
-golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
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/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -414,13 +406,13 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
-golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
+golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
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=
@@ -429,14 +421,16 @@ gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@@ -445,6 +439,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
+google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
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=
@@ -457,17 +453,16 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -475,43 +470,41 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
-gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
+gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k=
k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo=
-k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
-k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
-k8s.io/cli-runtime v0.25.4 h1:GTSBN7aKBrc2LqpdO30CmHQqJtRmotxV7XsMSP+QZIk=
-k8s.io/cli-runtime v0.25.4/go.mod h1:JGOw1CR8v4Mcz6cEKA7bFQe0bPrNn1l5sGAX1/Ke4Eg=
+k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM=
+k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
+k8s.io/cli-runtime v0.25.11 h1:GE2yNZm1tN+MJtw1SGMOLesLF7Kp7NVAVqRSTbXfu4o=
+k8s.io/cli-runtime v0.25.11/go.mod h1:r/nEINuHVEpgGhcd2WamU7hD1t/lMnSz8XM44Autltc=
k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8=
k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
-k8s.io/component-base v0.25.4 h1:n1bjg9Yt+G1C0WnIDJmg2fo6wbEU1UGMRiQSjmj7hNQ=
-k8s.io/component-base v0.25.4/go.mod h1:nnZJU8OP13PJEm6/p5V2ztgX2oyteIaAGKGMYb2L2cY=
-k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
-k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
-k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
-k8s.io/kubectl v0.25.4 h1:O3OA1z4V1ZyvxCvScjq0pxAP7ABgznr8UvnVObgI6Dc=
-k8s.io/kubectl v0.25.4/go.mod h1:CKMrQ67Bn2YCP26tZStPQGq62zr9pvzEf65A0navm8k=
-k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
-k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI=
+k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs=
+k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
+k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515 h1:OmK1d0WrkD3IPfkskvroRykOulHVHf0s0ZIFRjyt+UI=
+k8s.io/kube-openapi v0.0.0-20230525220651-2546d827e515/go.mod h1:kzo02I3kQ4BTtEfVLaPbjvCkX97YqGve33wzlb3fofQ=
+k8s.io/kubectl v0.25.11 h1:6bsft5Gan6BCvQ7cJbDRFjTm4Zfq8GuUYpsWAdVngYE=
+k8s.io/kubectl v0.25.11/go.mod h1:8mIfgkFgT+yJ8/TlmPW1qoRh46H2si9q5nW8id7i9iM=
+k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc=
+k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ=
sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
-sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
-sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
+sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/ops/hardhat/environment.go b/ops/hardhat/environment.go
index 9c29290..41d4204 100644
--- a/ops/hardhat/environment.go
+++ b/ops/hardhat/environment.go
@@ -4,8 +4,10 @@ import (
"fmt"
"github.com/rs/zerolog/log"
+
"github.com/goplugin/plugin-env/client"
"github.com/goplugin/plugin-env/environment"
+
"github.com/goplugin/plugin-starknet/ops/utils"
)
@@ -16,7 +18,7 @@ type Chart struct {
type Props struct {
NetworkName string `envconfig:"network_name"`
Simulated bool `envconfig:"network_simulated"`
- HttpURLs []string `envconfig:"http_url"`
+ HttpURLs []string `envconfig:"http_url"` //nolint:revive
WsURLs []string `envconfig:"ws_url"`
Values map[string]any
}
@@ -53,17 +55,17 @@ func (m Chart) GetValues() *map[string]any {
}
func (m Chart) ExportData(e *environment.Environment) error {
- devnetLocalHttp, err := e.Fwd.FindPort("hardhat:0", "hardhat", "http").As(client.LocalConnection, client.HTTP)
+ devnetLocalHTTP, err := e.Fwd.FindPort("hardhat:0", "hardhat", "http").As(client.LocalConnection, client.HTTP)
if err != nil {
return err
}
- devnetInternalHttp, err := e.Fwd.FindPort("hardhat:0", "hardhat", "http").As(client.RemoteConnection, client.HTTP)
+ devnetInternalHTTP, err := e.Fwd.FindPort("hardhat:0", "hardhat", "http").As(client.RemoteConnection, client.HTTP)
if err != nil {
return err
}
- e.URLs[m.Props.NetworkName] = append(e.URLs[m.Props.NetworkName], devnetLocalHttp)
- e.URLs[m.Props.NetworkName] = append(e.URLs[m.Props.NetworkName], devnetInternalHttp)
- log.Info().Str("Name", "Devnet").Str("URLs", devnetLocalHttp).Msg("Devnet network")
+ e.URLs[m.Props.NetworkName] = append(e.URLs[m.Props.NetworkName], devnetLocalHTTP)
+ e.URLs[m.Props.NetworkName] = append(e.URLs[m.Props.NetworkName], devnetInternalHTTP)
+ log.Info().Str("Name", "Devnet").Str("URLs", devnetLocalHTTP).Msg("Devnet network")
return nil
}
diff --git a/ops/localenv/main.go b/ops/localenv/main.go
index 38e34d4..fd457bb 100644
--- a/ops/localenv/main.go
+++ b/ops/localenv/main.go
@@ -12,7 +12,7 @@ import (
"github.com/goplugin/plugin-starknet/ops/utils"
)
-// TODO: consider extracting entire file to `plugin-relay/ops` or into a separate CLI tool
+// TODO: consider extracting entire file to `plugin-common/ops` or into a separate CLI tool
// this simply runs underlying functions but does not import them
// PODMAN:
@@ -28,10 +28,10 @@ func main() {
switch strings.ToLower(os.Args[1]) {
// create k8s cluster + resources
- case "create":
- run("create registry", "k3d", "registry", "create", "registry.localhost", "--port", "127.0.0.1:12345")
- run("create k8s cluster", "k3d", "cluster", "create", "local", "--api-port", "127.0.0.1:12346", "--registry-use", "k3d-registry.localhost:12345")
- run("switch k8s context", "kubectl", "config", "use-context", "k3d-local")
+ // case "create":
+ // run("create registry", "k3d", "registry", "create", "registry.localhost", "--port", "127.0.0.1:12345", "--default-network", "plugin")
+ // run("create k8s cluster", "k3d", "cluster", "create", "local", "--api-port", "127.0.0.1:12346", "--registry-use", "k3d-registry.localhost:12345")
+ // run("switch k8s context", "kubectl", "config", "use-context", "k3d-local")
// build and upload image to local registry
case "build":
context := "../../../plugin" // TODO: make this an arg
@@ -44,22 +44,23 @@ func main() {
if err := os.Chdir(utils.IntegrationTestsRoot); err != nil {
panic(err)
}
+ setEnvIfNotExists("PLUGIN_ENV_USER", "localenv")
setEnvIfNotExists("PLUGIN_IMAGE", "k3d-registry.localhost:12345/plugin")
setEnvIfNotExists("PLUGIN_VERSION", "local")
setEnvIfNotExists("KEEP_ENVIRONMENTS", "ALWAYS")
- setEnvIfNotExists("NODE_COUNT", "1")
+ setEnvIfNotExists("NODE_COUNT", "4")
setEnvIfNotExists("TTL", "900h")
run("start environment", "go", "test", "-count", "1", "-v", "-timeout", "30m", "--run", "^TestOCRBasic$", "./smoke")
// stop k8s namespace from environment
- case "stop":
- if len(os.Args) < 3 {
- panic("missing namespace argument")
- }
- run("stopping environment", "kubectl", "delete", "namespaces", os.Args[2])
+ // case "stop":
+ // if len(os.Args) < 3 {
+ // panic("missing namespace argument")
+ // }
+ // run("stopping environment", "kubectl", "delete", "namespaces", os.Args[2])
// delete removes the k8s cluster
- case "delete":
- run("remove k8s cluster", "k3d", "cluster", "delete", "local")
- run("remove registry", "k3d", "registry", "delete", "k3d-registry.localhost")
+ // case "delete":
+ // run("remove k8s cluster", "k3d", "cluster", "delete", "local")
+ // run("remove registry", "k3d", "registry", "delete", "k3d-registry.localhost")
default:
panic("unrecognized command")
}
diff --git a/ops/scripts/devnet-hardhat-down.sh b/ops/scripts/devnet-hardhat-down.sh
index 57baa59..d3096de 100755
--- a/ops/scripts/devnet-hardhat-down.sh
+++ b/ops/scripts/devnet-hardhat-down.sh
@@ -1,28 +1,28 @@
#!/usr/bin/env bash
# TODO: this script needs to be replaced with a predefined K8s enviroment
-echo "Cleaning up Starknet Devnet container..."
+echo "Cleaning up Hardhat container..."
-dpid=`docker ps | grep plugin-starknet.starknet-devnet | awk '{print $1}'`;
-echo "Checking for existing 'plugin-starknet.starknet-devnet' docker container..."
+dpid=`docker ps | grep plugin-starknet.hardhat | awk '{print $1}'`;
+echo "Checking for existing 'plugin-starknet.hardhat' docker container..."
if [ -z "$dpid" ]
then
- echo "No docker Starknet Devnet container running.";
+ echo "No docker Hardhat container running.";
else
docker kill $dpid;
- docker rm $dpid;
fi
+docker rm "plugin-starknet.hardhat";
-echo "Cleaning up Hardhat container..."
+echo "Cleaning up Starknet Devnet container..."
-dpid=`docker ps | grep plugin-starknet.hardhat | awk '{print $1}'`;
-echo "Checking for existing 'plugin-starknet.hardhat' docker container..."
+dpid=`docker ps | grep plugin-starknet.starknet-devnet | awk '{print $1}'`;
+echo "Checking for existing 'plugin-starknet.starknet-devnet' docker container..."
if [ -z "$dpid" ]
then
- echo "No docker Hardhat container running.";
+ echo "No docker Starknet Devnet container running.";
else
docker kill $dpid;
- docker rm $dpid;
fi
+docker rm "plugin-starknet.starknet-devnet";
echo "Cleanup finished."
diff --git a/ops/scripts/devnet-hardhat.sh b/ops/scripts/devnet-hardhat.sh
index 7559625..0b6d61b 100755
--- a/ops/scripts/devnet-hardhat.sh
+++ b/ops/scripts/devnet-hardhat.sh
@@ -1,23 +1,75 @@
#!/usr/bin/env bash
# TODO: this script needs to be replaced with a predefined K8s enviroment
-cpu_struct=`arch`;
-echo $cpu_struct;
+set -euo pipefail
-node --version;
+# cpu_struct=`arch`;
+# echo $cpu_struct;
+cpu_struct="linux"
# Clean up first
-bash "$(dirname -- "$0";)/devnet-hardhat-down.sh"
+bash "$(dirname -- "$0")/devnet-hardhat-down.sh"
echo "Checking CPU structure..."
-if [[ $cpu_struct == *"arm"* ]]
-then
- echo "Starting arm devnet container..."
- docker run -p 5050:5050 -p 8545:8545 -d --name plugin-starknet.starknet-devnet shardlabs/starknet-devnet:0.5.0;
+if [[ $cpu_struct == *"arm"* ]]; then
+ echo "Starting arm devnet container..."
+ container_version="${CONTAINER_VERSION:-a147b4cd72f9ce9d1fa665d871231370db0f51c7}-arm"
else
- echo "Starting i386 devnet container..."
- docker run -p 5050:5050 -p 8545:8545 -d --name plugin-starknet.starknet-devnet shardlabs/starknet-devnet:0.5.0;
+ echo "Starting i386 devnet container..."
+ container_version="${CONTAINER_VERSION:-a147b4cd72f9ce9d1fa665d871231370db0f51c7}"
fi
+echo "Starting starknet-devnet"
+
+# we need to replace the entrypoint because starknet-devnet's docker builds at 0.5.1 don't include cargo or gcc.
+docker run \
+ -p 127.0.0.1:5050:5050 \
+ -p 127.0.0.1:8545:8545 \
+ -d \
+ -e RUST_LOG=debug \
+ --name plugin-starknet.starknet-devnet \
+ "shardlabs/starknet-devnet-rs:${container_version}" \
+ --seed 0 \
+ --gas-price 1 \
+ --data-gas-price 1 \
+ --account-class cairo1
+
echo "Starting hardhat..."
docker run --net container:plugin-starknet.starknet-devnet -d --name plugin-starknet.hardhat ethereumoptimism/hardhat-node:nightly
+
+wait_for_container() {
+ local container_name="$1"
+ local ready_log="$2"
+ local start_time=$(date +%s)
+ local prev_output=""
+
+ echo "Waiting for container $container_name to become ready.."
+ while true; do
+ output=$(docker logs "$container_name" 2>&1)
+ if [[ "${output}" != "${prev_output}" ]]; then
+ echo -n "${output#$prev_output}"
+ prev_output="${output}"
+ fi
+
+ if [[ $output == *"$ready_log"* ]]; then
+ echo ""
+ echo "container $container_name is ready."
+ return
+ fi
+
+ current_time=$(date +%s)
+ elapsed_time=$((current_time - start_time))
+ if ((elapsed_time > 600)); then
+ echo "Error: Command did not become ready within 600 seconds"
+ exit 1
+ fi
+
+ sleep 3
+ done
+}
+
+# starknet-devnet startup is slow and requires compiling cairo.
+wait_for_container "plugin-starknet.starknet-devnet" "listening"
+
+# ethereumoptimism/hardhat-node is also slow and should be online before l1-l2 messaging tests are run
+wait_for_container "plugin-starknet.hardhat" "Any funds sent to them on Mainnet or any other live network WILL BE LOST."
diff --git a/ops/test_helpers.go b/ops/test_helpers.go
index b223222..1264487 100644
--- a/ops/test_helpers.go
+++ b/ops/test_helpers.go
@@ -1,17 +1,5 @@
package ops
-import (
- "github.com/goplugin/plugin-starknet/relayer/pkg/plugin/txm"
-)
-
-var (
- // seed = 0 keys for starknet-devnet
- PrivateKeys0Seed = txm.PrivateKeys0Seed
-
- DevnetClassHash = txm.DevnetClassHash
- DevnetSalt = txm.DevnetSalt
-)
-
// OCR2Config Default config for OCR2 for starknet
type OCR2Config struct {
F int `json:"f"`
@@ -32,7 +20,7 @@ type OffchainConfig struct {
RMax int `json:"rMax"`
S []int `json:"s"`
OffchainPublicKeys []string `json:"offchainPublicKeys"`
- PeerIds []string `json:"peerIds"`
+ PeerIDs []string `json:"peerIds"`
ReportingPluginConfig *ReportingPluginConfig `json:"reportingPluginConfig"`
MaxDurationQueryNanoseconds int `json:"maxDurationQueryNanoseconds"`
MaxDurationObservationNanoseconds int `json:"maxDurationObservationNanoseconds"`
@@ -56,27 +44,28 @@ var TestOCR2Config = OCR2Config{
// Transmitters: txKeys, // user defined
OnchainConfig: "",
OffchainConfig: &OffchainConfig{
- DeltaProgressNanoseconds: 8000000000,
- DeltaResendNanoseconds: 30000000000,
- DeltaRoundNanoseconds: 3000000000,
- DeltaGraceNanoseconds: 500000000,
- DeltaStageNanoseconds: 20000000000,
+ // todo: increase delta round but decrease delta stage
+ DeltaProgressNanoseconds: 150000000000, // 120s
+ DeltaResendNanoseconds: 150000000000, // 150s
+ DeltaRoundNanoseconds: 90000000000, // 90s
+ DeltaGraceNanoseconds: 5000000000, // 5s
+ DeltaStageNanoseconds: 30000000000, // 20s
RMax: 5,
- S: []int{1, 2},
+ S: []int{1, 1}, // Needs to array with length of transmitting nodes
// OffchainPublicKeys: offChainKeys, // user defined
- // PeerIds: peerIds, // user defined
+ // PeerIDs: peerIds, // user defined
ReportingPluginConfig: &ReportingPluginConfig{
AlphaReportInfinite: false,
AlphaReportPpb: 0,
AlphaAcceptInfinite: false,
AlphaAcceptPpb: 0,
- DeltaCNanoseconds: 0,
+ DeltaCNanoseconds: 1000000000,
},
- MaxDurationQueryNanoseconds: 0,
+ MaxDurationQueryNanoseconds: 2000000000,
MaxDurationObservationNanoseconds: 1000000000,
- MaxDurationReportNanoseconds: 200000000,
- MaxDurationShouldAcceptFinalizedReportNanoseconds: 200000000,
- MaxDurationShouldTransmitAcceptedReportNanoseconds: 200000000,
+ MaxDurationReportNanoseconds: 2000000000,
+ MaxDurationShouldAcceptFinalizedReportNanoseconds: 2000000000,
+ MaxDurationShouldTransmitAcceptedReportNanoseconds: 2000000000,
// ConfigPublicKeys: cfgKeys, // user defined
},
OffchainConfigVersion: 2,
diff --git a/package.json b/package.json
index 49a64f9..2a58fa2 100644
--- a/package.json
+++ b/package.json
@@ -15,10 +15,11 @@
"main": "packages-ts/starknet-gauntlet-cli/dist/index.js",
"bin": "packages-ts/starknet-gauntlet-cli/dist/index.js",
"scripts": {
- "gauntlet": "yarn build && node ./packages-ts/starknet-gauntlet-cli/dist/index.js",
+ "gauntlet": "node ./packages-ts/starknet-gauntlet-cli/dist/index.js",
"test": "yarn build && yarn workspaces run test",
"test:coverage": "yarn test --collectCoverage",
"test:ci": "yarn test --ci",
+ "eslint": "eslint -f json -o eslint-report.json ./packages-ts || true",
"lint": "tsc -b ./tsconfig.json",
"format": "yarn prettier --write .",
"format:check": "yarn prettier --check .",
@@ -37,17 +38,18 @@
],
"outputPath": "bin",
"assets": [
- "node_modules/@pluginv3.0-dev",
+ "node_modules/@plugin-dev",
"packages-ts/*/contract_artifacts/**/*",
"packages-ts/starknet-gauntlet-cli/networks/"
]
},
"devDependencies": {
"@changesets/cli": "^2.22.0",
- "@types/bn.js": "^5.1.1",
"@types/jest": "^28.1.0",
"@types/node": "^18.7.11",
- "bn.js": "^5.2.1",
+ "@typescript-eslint/eslint-plugin": "^6.7.2",
+ "@typescript-eslint/parser": "^6.7.2",
+ "eslint": "^8.49.0",
"jest": "^28.1.0",
"pkg": "^5.2.1",
"prettier": "2.1.1",
@@ -56,6 +58,6 @@
"typescript": "4.7.2"
},
"dependencies": {
- "starknet": "^5.2.0"
+ "starknet": "6.6.6"
}
}
diff --git a/packages-ts/integration-eqlabs-multisig/hardhat.config.ts b/packages-ts/integration-eqlabs-multisig/hardhat.config.ts
deleted file mode 100644
index ba93e3e..0000000
--- a/packages-ts/integration-eqlabs-multisig/hardhat.config.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { HardhatUserConfig } from 'hardhat/types'
-import '@shardlabs/starknet-hardhat-plugin'
-
-/**
- * @type import('hardhat/config').HardhatUserConfig
- */
-const config: HardhatUserConfig = {
- starknet: {
- venv: 'active',
- network: 'devnet',
- wallets: {
- OpenZeppelin: {
- accountName: 'OpenZeppelin',
- modulePath: 'starkware.starknet.wallets.open_zeppelin.OpenZeppelinAccount',
- accountPath: '~/.starknet_accounts',
- },
- },
- },
- networks: {
- devnet: {
- url: 'http://127.0.0.1:5050/',
- },
- },
- paths: {
- starknetArtifacts: '../../node_modules/starsign-multisig/starknet-artifacts/contracts',
- },
-}
-
-export default config
diff --git a/packages-ts/integration-eqlabs-multisig/package.json b/packages-ts/integration-eqlabs-multisig/package.json
deleted file mode 100644
index 8202297..0000000
--- a/packages-ts/integration-eqlabs-multisig/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "@pluginv3.0/starknet-integration-tests-eqlabs-multisig",
- "version": "1.0.0",
- "description": "Multisig integration test",
- "main": "index.js",
- "directories": {
- "test": "test"
- },
- "scripts": {
- "test": "npx hardhat --network localhost test"
- },
- "devDependencies": {
- "@changesets/cli": "^2.22.0",
- "@nomiclabs/hardhat-ethers": "^2.0.5",
- "@shardlabs/starknet-hardhat-plugin": "^0.8.0-alpha.0",
- "@types/chai": "^4.3.3",
- "@types/elliptic": "^6.4.14",
- "@types/mocha": "^9.1.1",
- "chai": "^4.3.6",
- "ethers": "^5.6.8",
- "hardhat": "^2.10.2",
- "starsign-multisig": "^0.3.0"
- }
-}
diff --git a/packages-ts/integration-eqlabs-multisig/test/Multisig.test.ts b/packages-ts/integration-eqlabs-multisig/test/Multisig.test.ts
deleted file mode 100644
index 4210dcb..0000000
--- a/packages-ts/integration-eqlabs-multisig/test/Multisig.test.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { expect } from 'chai'
-import { starknet } from 'hardhat'
-import { StarknetContract, Account } from 'hardhat/types/runtime'
-import { num, hash } from 'starknet'
-import { account } from '@pluginv3.0/starknet'
-
-describe('Multisig integration tests', function () {
- this.timeout(300_000)
-
- const opts = account.makeFunderOptsFromEnv()
- const funder = new account.Funder(opts)
-
- let account1: Account
- let account2: Account
- let account3: Account
-
- let multisig: StarknetContract
-
- before(async function () {
- account1 = await starknet.OpenZeppelinAccount.createAccount()
- account2 = await starknet.OpenZeppelinAccount.createAccount()
- account3 = await starknet.OpenZeppelinAccount.createAccount()
-
- await funder.fund([
- { account: account1.address, amount: 1e21 },
- { account: account2.address, amount: 1e21 },
- { account: account3.address, amount: 1e21 },
- ])
- await account1.deployAccount()
- await account2.deployAccount()
- await account3.deployAccount()
- })
-
- it('Deploy contract', async () => {
- let multisigFactory = await starknet.getContractFactory('Multisig')
- await account1.declare(multisigFactory)
-
- multisig = await account1.deploy(multisigFactory, {
- signers: [
- num.toBigInt(account1.starknetContract.address),
- num.toBigInt(account2.starknetContract.address),
- num.toBigInt(account3.starknetContract.address),
- ],
- threshold: 2,
- })
-
- expect(multisig).to.be.ok
- })
-
- it('should submit & confirm transaction', async () => {
- const nonce = 0
- const newThreshold = 1n
- const selector = hash.getSelectorFromName('set_threshold')
-
- const payload = {
- to: multisig.address,
- function_selector: selector,
- calldata: [newThreshold],
- nonce,
- }
-
- {
- const res = await account1.invoke(multisig, 'submit_transaction', payload)
- const txReciept = await starknet.getTransactionReceipt(res)
-
- expect(txReciept.events.length).to.equal(2)
- expect(txReciept.events[0].data.length).to.equal(3)
- expect(txReciept.events[0].data[1]).to.equal(num.toHex(num.toBigInt(nonce, 'hex')))
- }
-
- await account1.invoke(multisig, 'confirm_transaction', {
- nonce,
- })
-
- await account2.invoke(multisig, 'confirm_transaction', {
- nonce,
- })
-
- await account3.invoke(multisig, 'execute_transaction', {
- nonce,
- })
-
- {
- const res = await multisig.call('get_threshold')
- expect(res.threshold).to.equal(newThreshold)
- }
- })
-})
diff --git a/packages-ts/integration-eqlabs-multisig/tsconfig.json b/packages-ts/integration-eqlabs-multisig/tsconfig.json
deleted file mode 100644
index 8ac8056..0000000
--- a/packages-ts/integration-eqlabs-multisig/tsconfig.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": "../../tsconfig.base.json",
- "include": ["./test"],
- "files": ["./hardhat.config.ts"]
- }
-
\ No newline at end of file
diff --git a/packages-ts/starknet-gauntlet-argent/LICENSE b/packages-ts/starknet-gauntlet-argent/LICENSE
index fad7f7c..d13cc4b 100644
--- a/packages-ts/starknet-gauntlet-argent/LICENSE
+++ b/packages-ts/starknet-gauntlet-argent/LICENSE
@@ -1,7 +1,5 @@
The MIT License (MIT)
-Copyright (c) 2022 SmartContract Plugin, Ltd.
-
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
diff --git a/packages-ts/starknet-gauntlet-argent/README.md b/packages-ts/starknet-gauntlet-argent/README.md
index 864ad4e..7978397 100644
--- a/packages-ts/starknet-gauntlet-argent/README.md
+++ b/packages-ts/starknet-gauntlet-argent/README.md
@@ -2,14 +2,32 @@
## Account
-### Deploy
+### Declare
+
+This declare a new account class hash onto the L2 layer.
+```bash
+yarn gauntlet argent_account:declare --network=testnet
```
+
+Once it has been declared, you can use the class hash for a deployment (see Deploy command below)
+
+### Deploy
+
+```bash
yarn gauntlet argent_account:deploy --network=
```
+Optionally, you can deploy by referencing a previously deployed class hash
+
+```bash
+yarn gauntlet argent_account:deploy --classHash= --network=
+```
+
Note the contract address. The contract is not configured yet. A signer needs to be specified in it:
+
+
### Initialize
```bash
diff --git a/packages-ts/starknet-gauntlet-argent/package.json b/packages-ts/starknet-gauntlet-argent/package.json
index bafbbc8..c56e195 100644
--- a/packages-ts/starknet-gauntlet-argent/package.json
+++ b/packages-ts/starknet-gauntlet-argent/package.json
@@ -1,5 +1,5 @@
{
- "name": "@pluginv3.0/starknet-gauntlet-argent",
+ "name": "@plugin/starknet-gauntlet-argent",
"version": "0.0.1",
"description": "Starknet Gauntlet Argent contracts",
"keywords": [
@@ -25,7 +25,7 @@
"bundle": "yarn build && pkg ."
},
"dependencies": {
- "@pluginv3.0/gauntlet-core": "0.3.1",
- "@pluginv3.0/starknet-gauntlet": "*"
+ "@plugin/gauntlet-core": "0.3.1",
+ "@plugin/starknet-gauntlet": "*"
}
}
diff --git a/packages-ts/starknet-gauntlet-argent/src/commands/account/declare.ts b/packages-ts/starknet-gauntlet-argent/src/commands/account/declare.ts
new file mode 100644
index 0000000..48fac69
--- /dev/null
+++ b/packages-ts/starknet-gauntlet-argent/src/commands/account/declare.ts
@@ -0,0 +1,7 @@
+import { makeExecuteCommand, declareCommandConfig } from '@plugin/starknet-gauntlet'
+import { CATEGORIES } from '../../lib/categories'
+import { CONTRACT_LIST, accountContractLoader } from '../../lib/contracts'
+
+export default makeExecuteCommand(
+ declareCommandConfig(CONTRACT_LIST.ACCOUNT, CATEGORIES.ACCOUNT, accountContractLoader),
+)
diff --git a/packages-ts/starknet-gauntlet-argent/src/commands/account/deploy.ts b/packages-ts/starknet-gauntlet-argent/src/commands/account/deploy.ts
index 290d56e..84022fb 100644
--- a/packages-ts/starknet-gauntlet-argent/src/commands/account/deploy.ts
+++ b/packages-ts/starknet-gauntlet-argent/src/commands/account/deploy.ts
@@ -4,15 +4,30 @@ import {
ExecutionContext,
makeExecuteCommand,
Validation,
-} from '@pluginv3.0/starknet-gauntlet'
+ isValidAddress,
+} from '@plugin/starknet-gauntlet'
import { CATEGORIES } from '../../lib/categories'
import { accountContractLoader, CONTRACT_LIST } from '../../lib/contracts'
-type UserInput = {}
+type UserInput = {
+ classHash?: string
+}
type ContractInput = []
-const makeUserInput = async (flags, args): Promise => ({})
+const makeUserInput = async (flags, args): Promise => {
+ if (flags.input) return flags.input as UserInput
+ return {
+ classHash: flags.classHash,
+ }
+}
+
+const validateClassHash = async (input) => {
+ if (isValidAddress(input.classHash) || input.classHash === undefined) {
+ return true
+ }
+ throw new Error(`Invalid Class Hash: ${input.classHash}`)
+}
const makeContractInput = async (
input: UserInput,
@@ -35,11 +50,11 @@ const commandConfig: ExecuteCommandConfig = {
action: 'deploy',
ux: {
description: 'Deploys an Argent Labs Account contract',
- examples: [`${CATEGORIES.ACCOUNT}:deploy --network=`],
+ examples: [`${CATEGORIES.ACCOUNT}:deploy --classHash= --network=`],
},
makeUserInput,
makeContractInput,
- validations: [],
+ validations: [validateClassHash],
loadContract: accountContractLoader,
hooks: {
beforeExecute,
diff --git a/packages-ts/starknet-gauntlet-argent/src/commands/account/index.ts b/packages-ts/starknet-gauntlet-argent/src/commands/account/index.ts
index dc9ac9a..ba3a7ad 100644
--- a/packages-ts/starknet-gauntlet-argent/src/commands/account/index.ts
+++ b/packages-ts/starknet-gauntlet-argent/src/commands/account/index.ts
@@ -1,4 +1,5 @@
import Deploy from './deploy'
import Initialize from './initialize'
+import Declare from './declare'
-export default [Deploy, Initialize]
+export default [Deploy, Initialize, Declare]
diff --git a/packages-ts/starknet-gauntlet-argent/src/commands/account/initialize.ts b/packages-ts/starknet-gauntlet-argent/src/commands/account/initialize.ts
index 674d6cb..05e2037 100644
--- a/packages-ts/starknet-gauntlet-argent/src/commands/account/initialize.ts
+++ b/packages-ts/starknet-gauntlet-argent/src/commands/account/initialize.ts
@@ -4,7 +4,7 @@ import {
ExecuteCommandConfig,
makeExecuteCommand,
Validation,
-} from '@pluginv3.0/starknet-gauntlet'
+} from '@plugin/starknet-gauntlet'
import { ec } from 'starknet'
import { CATEGORIES } from '../../lib/categories'
import { accountContractLoader, CONTRACT_LIST } from '../../lib/contracts'
@@ -38,7 +38,9 @@ const beforeExecute: BeforeExecute = (
input,
deps,
) => async () => {
- deps.logger.info(`About to deploy an Account Contract with public key ${input.contract[0]}`)
+ deps.logger.info(
+ `About to deploy an Argent Account Contract with public key ${input.contract[0]}`,
+ )
if (input.user.privateKey) {
await deps.prompt(`The generated private key will be shown next, continue?`)
deps.logger.line()
diff --git a/packages-ts/starknet-gauntlet-argent/src/lib/contracts.ts b/packages-ts/starknet-gauntlet-argent/src/lib/contracts.ts
index 8194ef5..d16f713 100644
--- a/packages-ts/starknet-gauntlet-argent/src/lib/contracts.ts
+++ b/packages-ts/starknet-gauntlet-argent/src/lib/contracts.ts
@@ -5,10 +5,12 @@ export enum CONTRACT_LIST {
ACCOUNT = 'argent_account',
}
-export const loadContract = (name: CONTRACT_LIST): CompiledContract => {
- return json.parse(
- fs.readFileSync(`${__dirname}/../../artifacts/abi/${name}.json`).toString('ascii'),
- )
+export const loadContract = (name: CONTRACT_LIST): any => {
+ return {
+ contract: json.parse(
+ fs.readFileSync(`${__dirname}/../../artifacts/abi/${name}.json`).toString('utf8'),
+ ),
+ }
}
export const accountContractLoader = () => loadContract(CONTRACT_LIST.ACCOUNT)
diff --git a/packages-ts/starknet-gauntlet-cli/LICENSE b/packages-ts/starknet-gauntlet-cli/LICENSE
index fad7f7c..d13cc4b 100644
--- a/packages-ts/starknet-gauntlet-cli/LICENSE
+++ b/packages-ts/starknet-gauntlet-cli/LICENSE
@@ -1,7 +1,5 @@
The MIT License (MIT)
-Copyright (c) 2022 SmartContract Plugin, Ltd.
-
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
diff --git a/packages-ts/starknet-gauntlet-cli/README.md b/packages-ts/starknet-gauntlet-cli/README.md
index ac78265..9a6e93a 100644
--- a/packages-ts/starknet-gauntlet-cli/README.md
+++ b/packages-ts/starknet-gauntlet-cli/README.md
@@ -2,9 +2,9 @@
This packages expose the commands to be used as a CLI of the following packages:
-- @pluginv3.0/starknet-gauntlet-example
-- @pluginv3.0/starknet-gauntlet-account
-- @pluginv3.0/starknet-gauntlet-ocr2
+- @plugin/starknet-gauntlet-example
+- @plugin/starknet-gauntlet-account
+- @plugin/starknet-gauntlet-ocr2
## Setup
diff --git a/packages-ts/starknet-gauntlet-cli/package.json b/packages-ts/starknet-gauntlet-cli/package.json
index 8b17aa9..844c10e 100644
--- a/packages-ts/starknet-gauntlet-cli/package.json
+++ b/packages-ts/starknet-gauntlet-cli/package.json
@@ -1,5 +1,5 @@
{
- "name": "@pluginv3.0/starknet-gauntlet-cli",
+ "name": "@plugin/starknet-gauntlet-cli",
"version": "0.0.1",
"description": "Starknet Gauntlet CLI",
"keywords": [
@@ -25,14 +25,14 @@
"bundle": "yarn build && pkg ."
},
"dependencies": {
- "@pluginv3.0/gauntlet-core": "0.3.1",
- "@pluginv3.0/starknet-gauntlet-oz": "*",
- "@pluginv3.0/starknet-gauntlet-argent": "*",
- "@pluginv3.0/starknet-gauntlet-example": "*",
- "@pluginv3.0/starknet-gauntlet-ocr2": "*",
- "@pluginv3.0/starknet-gauntlet-token": "*",
- "@pluginv3.0/starknet-gauntlet-multisig": "*",
- "@pluginv3.0/starknet-gauntlet-emergency-protocol": "*",
- "@pluginv3.0/starknet-gauntlet-ledger": "*"
+ "@plugin/gauntlet-core": "0.3.1",
+ "@plugin/starknet-gauntlet-oz": "*",
+ "@plugin/starknet-gauntlet-argent": "*",
+ "@plugin/starknet-gauntlet-example": "*",
+ "@plugin/starknet-gauntlet-ocr2": "*",
+ "@plugin/starknet-gauntlet-token": "*",
+ "@plugin/starknet-gauntlet-multisig": "*",
+ "@plugin/starknet-gauntlet-emergency-protocol": "*",
+ "@plugin/starknet-gauntlet-ledger": "*"
}
}
diff --git a/packages-ts/starknet-gauntlet-cli/src/index.ts b/packages-ts/starknet-gauntlet-cli/src/index.ts
index fae1de1..caedbfa 100644
--- a/packages-ts/starknet-gauntlet-cli/src/index.ts
+++ b/packages-ts/starknet-gauntlet-cli/src/index.ts
@@ -1,32 +1,32 @@
import {
executeCommands as OCR2ExecuteCommands,
inspectionCommands as OCR2InspectionCommands,
-} from '@pluginv3.0/starknet-gauntlet-ocr2'
+} from '@plugin/starknet-gauntlet-ocr2'
import {
executeCommands as ExampleExecuteCommands,
inspectionCommands as ExampleInspectionsCommands,
-} from '@pluginv3.0/starknet-gauntlet-example'
-import { Commands as OZCommands } from '@pluginv3.0/starknet-gauntlet-oz'
+} from '@plugin/starknet-gauntlet-example'
+import { Commands as OZCommands } from '@plugin/starknet-gauntlet-oz'
import {
L2Commands as L2StarkgateCommands,
InspectionCommands as StarkgateInspectionCommands,
-} from '@pluginv3.0/starknet-gauntlet-token'
-import { Commands as ArgentCommands } from '@pluginv3.0/starknet-gauntlet-argent'
+} from '@plugin/starknet-gauntlet-token'
+import { Commands as ArgentCommands } from '@plugin/starknet-gauntlet-argent'
import {
L1Commands as L1EmergencyProtocolCommands,
L2Commands as L2EmergencyProtocolCommands,
L2InspectionCommands as L2EmergencyProtocolInspectionCommands,
-} from '@pluginv3.0/starknet-gauntlet-emergency-protocol'
+} from '@plugin/starknet-gauntlet-emergency-protocol'
import {
executeCommands as MultisigExecuteCommands,
inspectionCommands as MultisigInspectionCommands,
wrapCommand as multisigWrapCommand,
-} from '@pluginv3.0/starknet-gauntlet-multisig'
+} from '@plugin/starknet-gauntlet-multisig'
-import { executeCLI } from '@pluginv3.0/gauntlet-core'
+import { executeCLI } from '@plugin/gauntlet-core'
import { existsSync } from 'fs'
import path from 'path'
-import { io, logger, prompt } from '@pluginv3.0/gauntlet-core/dist/utils'
+import { io, logger, prompt } from '@plugin/gauntlet-core/dist/utils'
import {
CommandCtor,
Dependencies,
@@ -35,15 +35,15 @@ import {
InspectCommandInstance,
makeProvider,
makeWallet as makeDefaultWallet,
-} from '@pluginv3.0/starknet-gauntlet'
+} from '@plugin/starknet-gauntlet'
import {
EVMExecuteCommandInstance,
CommandCtor as EVMCommandCtor,
makeWallet as EVMMakeWallet,
makeProvider as EVMMakeProvider,
EVMDependencies,
-} from '@pluginv3.0/evm-gauntlet'
-import { makeWallet as makeLedgerWallet } from '@pluginv3.0/starknet-gauntlet-ledger'
+} from '@plugin/evm-gauntlet'
+import { makeWallet as makeLedgerWallet } from '@plugin/starknet-gauntlet-ledger'
export const noopPrompt: typeof prompt = async () => {}
@@ -64,6 +64,7 @@ const registerExecuteCommand = (
billingAccessController: process.env.BILLING_ACCESS_CONTROLLER,
link: process.env.PLI,
secret: flags.secret || process.env.SECRET,
+ randomSecret: flags.randomSecret || process.env.RANDOM_SECRET,
withLedger: !!flags.withLedger || !!process.env.WITH_LEDGER,
ledgerPath: (flags.ledgerPath as string) || process.env.LEDGER_PATH,
}
diff --git a/packages-ts/starknet-gauntlet-emergency-protocol/LICENSE b/packages-ts/starknet-gauntlet-emergency-protocol/LICENSE
index fad7f7c..d13cc4b 100644
--- a/packages-ts/starknet-gauntlet-emergency-protocol/LICENSE
+++ b/packages-ts/starknet-gauntlet-emergency-protocol/LICENSE
@@ -1,7 +1,5 @@
The MIT License (MIT)
-Copyright (c) 2022 SmartContract Plugin, Ltd.
-
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
diff --git a/packages-ts/starknet-gauntlet-emergency-protocol/README.md b/packages-ts/starknet-gauntlet-emergency-protocol/README.md
index 54ca2bb..e89664a 100644
--- a/packages-ts/starknet-gauntlet-emergency-protocol/README.md
+++ b/packages-ts/starknet-gauntlet-emergency-protocol/README.md
@@ -19,12 +19,16 @@ This deploys a new instance of the `StarknetValidator` contract on **L1**
`