diff --git a/.github/actions/build-sign-publish-chainlink/action.yml b/.github/actions/build-sign-publish-chainlink/action.yml index feef0e78d3b..19b5c733e67 100644 --- a/.github/actions/build-sign-publish-chainlink/action.yml +++ b/.github/actions/build-sign-publish-chainlink/action.yml @@ -10,6 +10,7 @@ inputs: required: false dockerfile: + description: Path to the Dockerfile (relative to the repo root) default: core/chainlink.Dockerfile required: false ecr-hostname: @@ -23,6 +24,11 @@ inputs: default: chainlink/chainlink required: false ecr-tag-suffix: + description: Docker image tag suffix + required: false + git-commit-sha: + description: Git commit SHA used as metadata when building the application (appears in logs) + default: ${{ github.sha }} required: false aws-role-to-assume: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action @@ -74,7 +80,7 @@ runs: ) SHARED_BUILD_ARGS=$(cat << EOF - COMMIT_SHA=${{ github.sha }} + COMMIT_SHA=${{ inputs.git-commit-sha }} EOF ) @@ -195,7 +201,7 @@ runs: - if: inputs.sign-images == 'true' name: Install cosign - uses: sigstore/cosign-installer@581838fbedd492d2350a9ecd427a95d6de1e5d01 # v2.1.0 + uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 with: cosign-release: "v1.6.0" diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index 4384fe23e65..c4b39b4d7af 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -48,7 +48,7 @@ runs: file: ./integration-tests/test.Dockerfile build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image - IMAGE_VERSION=v0.32.9 + IMAGE_VERSION=v0.38.2 SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml new file mode 100644 index 00000000000..5c4882e2684 --- /dev/null +++ b/.github/actions/golangci-lint/action.yml @@ -0,0 +1,77 @@ +name: CI lint for Golang +description: Runs CI lint for Golang +inputs: + # general inputs + name: + description: Name of the lint action + default: lint + go-directory: + description: Go directory to run commands from + default: "." + # setup-go inputs + only-modules: + description: Set to 'true' to only cache modules + default: "false" + cache-version: + description: Set this to cache bust + default: "1" + go-version-file: + description: Set where the go version file is located at + default: "go.mod" + go-module-file: + description: Set where the go module file is located at + default: "go.sum" + # grafana cloud inputs + gc-host: + description: "grafana cloud hostname" + gc-basic-auth: + description: "grafana cloud basic auth" + +runs: + using: composite + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: ./.github/actions/setup-go + with: + only-modules: ${{ inputs.only-modules }} + cache-version: ${{ inputs.cache-version }} + go-version-file: ${{ inputs.go-version-file }} + go-module-file: ${{ inputs.go-module-file }} + - name: Touching core/web/assets/index.html + shell: bash + run: mkdir -p core/web/assets && touch core/web/assets/index.html + - name: Build binary + if: ${{ inputs.go-directory == '.' }} + shell: bash + run: go build ./... + - name: Build binary + if: ${{ inputs.go-directory != '.' }} + working-directory: ${{ inputs.go-directory }} + shell: bash + run: go build + - name: golangci-lint + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 + with: + version: v1.55.0 + # We already cache these directories in setup-go + skip-pkg-cache: true + skip-build-cache: true + # only-new-issues is only applicable to PRs, otherwise it is always set to false + only-new-issues: true + args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml + working-directory: ${{ inputs.go-directory }} + - name: Store lint report artifact + if: always() + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + with: + name: golangci-lint-report + path: ${{ inputs.go-directory }}/golangci-lint-report.xml + - name: Collect Metrics + if: always() + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + with: + basic-auth: ${{ inputs.gc-basic-auth }} + hostname: ${{ inputs.gc-host }} + this-job-name: ${{ inputs.name }} + continue-on-error: true diff --git a/.github/actions/goreleaser-build-sign-publish/action.yml b/.github/actions/goreleaser-build-sign-publish/action.yml index 0cc144564c0..a9f32337221 100644 --- a/.github/actions/goreleaser-build-sign-publish/action.yml +++ b/.github/actions/goreleaser-build-sign-publish/action.yml @@ -84,7 +84,7 @@ runs: version: ${{ inputs.zig-version }} - name: Setup cosign if: inputs.enable-cosign == 'true' - uses: sigstore/cosign-installer@581838fbedd492d2350a9ecd427a95d6de1e5d01 # v2.1.0 + uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 with: cosign-release: ${{ inputs.cosign-version }} - name: Login to docker registry diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index 996fb4ac507..eba01521068 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -1,53 +1,64 @@ name: Setup Go -description: Setup Golang with efficient caching +description: Setup Golang with efficient caching inputs: only-modules: description: Set to 'true' to only cache modules - default: 'false' + default: "false" cache-version: description: Set this to cache bust default: "1" + go-version-file: + description: Set where the go version file is located at + default: "go.mod" + go-module-file: + description: Set where the go module file is located at + default: "go.sum" runs: using: composite steps: - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version-file: "go.mod" - cache: false + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: ${{ inputs.go-version-file }} + cache: false - - name: Get branch name - if: ${{ inputs.only-modules == 'false' }} - id: branch-name - uses: tj-actions/branch-names@2e5354c6733793113f416314375826df030ada23 #v6.5 + - name: Get branch name + if: ${{ inputs.only-modules == 'false' }} + id: branch-name + uses: tj-actions/branch-names@2e5354c6733793113f416314375826df030ada23 #v6.5 - - name: Set go cache keys - shell: bash - id: go-cache-dir - run: | - echo "gomodcache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT - echo "gobuildcache=$(go env GOCACHE)" >> $GITHUB_OUTPUT + - name: Set go cache keys + shell: bash + id: go-cache-dir + run: | + echo "gomodcache=$(go env GOMODCACHE)" >> $GITHUB_OUTPUT + echo "gobuildcache=$(go env GOCACHE)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - name: Cache Go Modules - with: - path: | - ${{ steps.go-cache-dir.outputs.gomodcache }} - # The lifetime of go modules is much higher than the build outputs, so we increase cache efficiency - # here by not having the primary key contain the branch name - key: ${{ runner.os }}-gomod-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }} - restore-keys: | - ${{ runner.os }}-gomod-${{ inputs.cache-version }}- + - name: Set go module path + id: go-module-path + shell: bash + run: echo "path=./${{ inputs.go-module-file }}" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - if: ${{ inputs.only-modules == 'false' }} - name: Cache Go Build Outputs - with: - path: | - ${{ steps.go-cache-dir.outputs.gobuildcache }} - # The lifetime of go build outputs is pretty short, so we make our primary cache key be the branch name - key: ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }}-${{ steps.branch-name.outputs.current_branch }} - restore-keys: | - ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles('./go.sum') }}- - ${{ runner.os }}-gobuild-${{ inputs.cache-version }}- + - uses: actions/cache@v3 + name: Cache Go Modules + with: + path: | + ${{ steps.go-cache-dir.outputs.gomodcache }} + # The lifetime of go modules is much higher than the build outputs, so we increase cache efficiency + # here by not having the primary key contain the branch name + key: ${{ runner.os }}-gomod-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }} + restore-keys: | + ${{ runner.os }}-gomod-${{ inputs.cache-version }}- + + - uses: actions/cache@v3 + if: ${{ inputs.only-modules == 'false' }} + name: Cache Go Build Outputs + with: + path: | + ${{ steps.go-cache-dir.outputs.gobuildcache }} + # The lifetime of go build outputs is pretty short, so we make our primary cache key be the branch name + key: ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }}-${{ steps.branch-name.outputs.current_branch }} + restore-keys: | + ${{ runner.os }}-gobuild-${{ inputs.cache-version }}-${{ hashFiles(steps.go-module-path.output.path) }}- + ${{ runner.os }}-gobuild-${{ inputs.cache-version }}- diff --git a/.github/actions/setup-postgres/.env b/.github/actions/setup-postgres/.env index 8954e9d2f3b..47ed8d9bcd5 100644 --- a/.github/actions/setup-postgres/.env +++ b/.github/actions/setup-postgres/.env @@ -1,5 +1,5 @@ POSTGRES_USER=postgres -POSTGRES_OPTIONS="-c max_connections=1000 -c shared_buffers=2GB" +POSTGRES_OPTIONS="-c max_connections=1000 -c shared_buffers=2GB -c log_lock_waits=true" POSTGRES_PASSWORD=postgres POSTGRES_DB=chainlink_test POSTGRES_HOST_AUTH_METHOD=trust diff --git a/.github/cr.yaml b/.github/cr.yaml new file mode 100644 index 00000000000..b526aa963f9 --- /dev/null +++ b/.github/cr.yaml @@ -0,0 +1,2 @@ +pages_branch: helm-release +packages_with_index: true diff --git a/.github/tracing/README.md b/.github/tracing/README.md new file mode 100644 index 00000000000..6988383ca7b --- /dev/null +++ b/.github/tracing/README.md @@ -0,0 +1,5 @@ +# Distributed Tracing + +These config files are for an OTEL collector, grafana Tempo, and a grafana UI instance to run as containers on the same network. + +A localhost client can send gRPC calls to the server. The gRPC server is instrumented with open telemetry traces, which are sent to the OTEL collector and forwarded to the Tempo backend. The grafana UI can then read the trace data from the Tempo backend. \ No newline at end of file diff --git a/.github/tracing/grafana-datasources.yaml b/.github/tracing/grafana-datasources.yaml new file mode 100644 index 00000000000..098b06ec760 --- /dev/null +++ b/.github/tracing/grafana-datasources.yaml @@ -0,0 +1,18 @@ +apiVersion: 1 + +datasources: +- name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus \ No newline at end of file diff --git a/.github/tracing/local-smoke-docker-compose.yaml b/.github/tracing/local-smoke-docker-compose.yaml new file mode 100644 index 00000000000..e0e60a675e5 --- /dev/null +++ b/.github/tracing/local-smoke-docker-compose.yaml @@ -0,0 +1,46 @@ +version: "3" +services: + + # ... the OpenTelemetry Collector configured to receive traces and export to Tempo ... + otel-collector: + image: otel/opentelemetry-collector:0.61.0 + command: [ "--config=/etc/otel-collector.yaml" ] + volumes: + - ./otel-collector.yaml:/etc/otel-collector.yaml + ports: + - "4317:4317" # otlp grpc + depends_on: + - tempo + networks: + - tracing-network + + # .. Which accepts requests from grafana ... + tempo: + image: grafana/tempo:latest + command: [ "-config.file=/etc/tempo.yaml" ] + volumes: + - ./tempo.yaml:/etc/tempo.yaml + - ./tempo-data:/tmp/tempo + ports: + - "4317" # otlp grpc + networks: + - tracing-network + + grafana: + image: grafana/grafana:9.4.3 + volumes: + - ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceqlEditor + ports: + - "3000:3000" + networks: + - tracing-network + +networks: + tracing-network: + name: tracing + driver: bridge \ No newline at end of file diff --git a/.github/tracing/otel-collector.yaml b/.github/tracing/otel-collector.yaml new file mode 100644 index 00000000000..fb8721cba20 --- /dev/null +++ b/.github/tracing/otel-collector.yaml @@ -0,0 +1,15 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: "0.0.0.0:4317" +exporters: + otlp: + endpoint: tempo:4317 + tls: + insecure: true +service: + pipelines: + traces: + receivers: [otlp] + exporters: [otlp] \ No newline at end of file diff --git a/.github/tracing/tempo.yaml b/.github/tracing/tempo.yaml new file mode 100644 index 00000000000..e61f744f78b --- /dev/null +++ b/.github/tracing/tempo.yaml @@ -0,0 +1,24 @@ +server: + http_listen_port: 3200 + +distributor: + receivers: + otlp: + protocols: + http: + grpc: + +ingester: + max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally + +compactor: + compaction: + block_retention: 1h # overall Tempo trace retention. set for demo purposes + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the the wal locally + local: + path: /tmp/tempo/blocks \ No newline at end of file diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index 3eb44ea9c65..3d7466faedd 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -6,7 +6,7 @@ on: description: Chainlink image version to use required: true type: string - default: 2.0.0 + default: 2.5.0 chainlinkImage: description: Chainlink image repo to use required: true @@ -128,7 +128,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 438264e222d..032670c39a3 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -10,6 +10,16 @@ on: description: Chainlink image repo to use (Leave empty to build from head/ref) required: false type: string + chainlinkVersionUpdate: + description: Chainlink image version to use initially for upgrade test + default: latest + required: true + type: string + chainlinkImageUpdate: + description: Chainlink image repo to use initially for upgrade test + required: true + default: public.ecr.aws/chainlink/chainlink + type: string env: ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} @@ -36,7 +46,7 @@ jobs: - name: Collect Metrics if: inputs.chainlinkImage == '' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -81,7 +91,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -130,8 +140,8 @@ jobs: command: -run ^TestAutomationReorg$ ./reorg - name: upgrade suite: smoke - nodes: 1 - os: ubuntu-latest + nodes: 3 + os: ubuntu20.04-8cores-32GB pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED command: -run ^TestAutomationNodeUpgrade$ ./smoke @@ -150,14 +160,16 @@ jobs: echo "image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT echo "version=${{ github.sha }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT + echo "upgrade_image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT else echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT + echo "upgrade_image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT fi if [[ "${{ matrix.tests.name }}" == "upgrade" ]]; then - echo "image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT - echo "version=develop" >>$GITHUB_OUTPUT + echo "image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT + echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 @@ -167,13 +179,14 @@ jobs: PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} SELECTED_NETWORKS: ${{ matrix.tests.network }} TEST_SUITE: ${{ matrix.tests.suite }} - TEST_UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} - TEST_UPGRADE_IMAGE: ${{ env.CHAINLINK_IMAGE }} + UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} + UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }} with: - test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ steps.determine-build.outputs.image }} cl_image_tag: ${{ steps.determine-build.outputs.version }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_location: ./integration-tests/${{ matrix.tests.suite }}/logs publish_check_name: Automation On Demand Results ${{ matrix.tests.name }} token: ${{ secrets.GITHUB_TOKEN }} @@ -192,7 +205,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml index 4384956da3c..cba8edba3e2 100644 --- a/.github/workflows/build-publish-develop.yml +++ b/.github/workflows/build-publish-develop.yml @@ -34,6 +34,13 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: ref: ${{ env.GIT_REF }} + # When this is ran from manual workflow_dispatch, the github.sha may be + # different than the checked out commit sha. The core build uses this + # commit sha as build metadata, so we need to make sure it's correct. + - name: Get checked out git ref + if: github.event.inputs.git_ref + id: git-ref + run: echo "checked-out=$(git rev-parse HEAD)" | tee -a "${GITHUB_OUTPUT}" - name: Build, sign and publish chainlink image uses: ./.github/actions/build-sign-publish-chainlink with: @@ -45,10 +52,11 @@ jobs: ecr-image-name: chainlink ecr-tag-suffix: ${{ matrix.image.tag-suffix }} dockerfile: ${{ matrix.image.dockerfile }} + git-commit-sha: ${{ steps.git-ref.outputs.checked-out || github.sha }} - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml index e0d8a77b570..9aa7b9accc5 100644 --- a/.github/workflows/build-publish.yml +++ b/.github/workflows/build-publish.yml @@ -50,7 +50,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 42efe1dadab..9931137d637 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 7378a227ecb..a8e6e266a96 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Check for changed files id: changedfiles - uses: umani/changed-files@0239328a3a6268aad16af7c3e4efc78e32d6c0f0 # Version 4.0.1 + uses: umani/changed-files@d7f842d11479940a6036e3aacc6d35523e6ba978 # Version 4.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} pattern: '^docs/CHANGELOG.*$' @@ -31,7 +31,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml new file mode 100644 index 00000000000..97225e46557 --- /dev/null +++ b/.github/workflows/ci-chaincli.yml @@ -0,0 +1,26 @@ +name: chaincli CI + +on: + push: + paths: + - "core/scripts/chaincli/**" + pull_request: + paths: + - "core/scripts/chaincli/**" + +jobs: + golangci: + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }} + name: chaincli-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Golang Lint + uses: ./.github/actions/golangci-lint + with: + name: chaincli-lint + go-directory: core/scripts/chaincli + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 245b282f2da..d6991bb4e67 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -23,36 +23,11 @@ jobs: runs-on: ubuntu20.04-8cores-32GB steps: - uses: actions/checkout@v4 - - name: Setup Go - uses: ./.github/actions/setup-go - - name: Touching core/web/assets/index.html - run: mkdir -p core/web/assets && touch core/web/assets/index.html - - name: Build binary - run: go build ./... - - name: golangci-lint - uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 - with: - version: v1.54.2 - # We already cache these directories in setup-go - skip-pkg-cache: true - skip-build-cache: true - # only-new-issues is only applicable to PRs, otherwise it is always set to false - only-new-issues: true - args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml - - name: Store lint report artifact - if: always() - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 - with: - name: golangci-lint-report - path: golangci-lint-report.xml - - name: Collect Metrics - if: always() - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + - name: Golang Lint + uses: ./.github/actions/golangci-lint with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: lint - continue-on-error: true + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} core: strategy: @@ -85,7 +60,7 @@ jobs: - name: Download Go vendor packages run: go mod download - name: Build binary - run: go build -tags test -o chainlink.test . + run: go build -o chainlink.test . - name: Setup DB run: ./chainlink.test local db preparetest - name: Increase Race Timeout @@ -100,11 +75,18 @@ jobs: USE_TEE: false run: ./tools/bin/${{ matrix.cmd }} ./... - name: Print Filtered Test Results - if: failure() + if: ${{ failure() && matrix.cmd == 'go_core_tests' }} uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 with: results-file: ./output.txt output-file: ./output-short.txt + - name: Print Races + if: ${{ failure() && matrix.cmd == 'go_core_race_tests' }} + run: find race.* | xargs cat + - name: Print postgres logs + if: always() + run: docker compose logs postgres | tee ../../../postgres_logs.txt + working-directory: ./.github/actions/setup-postgres - name: Store logs artifacts if: always() uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 @@ -115,10 +97,7 @@ jobs: ./output-short.txt ./race.* ./coverage.txt - - name: Print postgres logs - if: always() - run: docker compose logs postgres - working-directory: ./.github/actions/setup-postgres + ./postgres_logs.txt - name: Notify Slack if: ${{ failure() && matrix.cmd == 'go_core_race_tests' && github.event.schedule != '' }} uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 @@ -130,7 +109,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -163,7 +142,7 @@ jobs: - name: Download Go vendor packages run: go mod download - name: Build binary - run: go build -tags test -o chainlink.test . + run: go build -o chainlink.test . - name: Setup DB run: ./chainlink.test local db preparetest - name: Load test outputs @@ -224,7 +203,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -234,7 +213,7 @@ jobs: clean: name: Clean Go Tidy & Generate if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} - runs-on: ubuntu-latest + runs-on: ubuntu20.04-8cores-32GB defaults: run: shell: bash @@ -262,7 +241,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 58b38015a63..86f2515e26d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -45,7 +45,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/delete-deployments.yml b/.github/workflows/delete-deployments.yml index 83a4ba8dfce..a3d3100516d 100644 --- a/.github/workflows/delete-deployments.yml +++ b/.github/workflows/delete-deployments.yml @@ -24,7 +24,7 @@ jobs: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index 4bcab9091dd..ebfe1b947a9 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -47,7 +47,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml index 3a3236cc978..9e9b088033e 100644 --- a/.github/workflows/goreleaser-build-publish-develop.yml +++ b/.github/workflows/goreleaser-build-publish-develop.yml @@ -39,7 +39,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml index 8a14ff1a7e6..e80d758d810 100644 --- a/.github/workflows/helm-publish.yml +++ b/.github/workflows/helm-publish.yml @@ -1,18 +1,39 @@ name: Helm Publish on: - pull_request: - types: [ labeled ] + workflow_dispatch: jobs: helm_release: - if: ${{ github.event.label.name == 'helm_release' }} runs-on: ubuntu-latest + environment: build-develop + permissions: + id-token: write + contents: read steps: - - uses: actions/checkout@v1 - - name: Release helm chart - uses: J12934/helm-gh-pages-action@master + - name: Checkout repo + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + + - name: Configure aws credentials + uses: aws-actions/configure-aws-credentials@50ac8dd1e1b10d09dac7b8727528b91bed831ac0 # v3.0.2 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_GATI }} + role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Get Github Token + id: get-gh-token + uses: smartcontractkit/chainlink-github-actions/github-app-token-issuer@main + with: + url: ${{ secrets.GATI_LAMBDA_FUNCTION_URL }} + + - name: Install Helm + uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + + - name: Run chart-releaser + uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0 with: - charts-folder: charts - deploy-branch: helm-release - access-token: ${{ secrets.HELM_PUSH_TOKEN }} \ No newline at end of file + charts_dir: charts + config: .github/cr.yaml + env: + CR_TOKEN: "${{ steps.get-gh-token.outputs.access-token }}" diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 8e1bfdd06c4..a9aa2c35df1 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -53,7 +53,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -79,7 +79,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -99,7 +99,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml index d0ce62a71bb..c71b83d1c4d 100644 --- a/.github/workflows/integration-tests-publish.yml +++ b/.github/workflows/integration-tests-publish.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index fd61f9b3384..aadb14f1284 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -45,7 +45,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -53,7 +53,6 @@ jobs: continue-on-error: true outputs: src: ${{ steps.changes.outputs.src }} - build-chainlink: environment: integration permissions: @@ -75,7 +74,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -111,7 +110,7 @@ jobs: echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY build-test-image: - if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')) || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'schedule' || contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') environment: integration permissions: id-token: write @@ -123,7 +122,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -229,7 +228,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -271,6 +270,11 @@ jobs: nodes: 1 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-ocr2-evm-simulated + - name: ocr2 + nodes: 1 + os: ubuntu20.04-8cores-32GB + pyroscope_env: ci-smoke-ocr2-evm-simulated + tag_suffix: "-plugins" - name: runlog nodes: 1 os: ubuntu-latest @@ -296,7 +300,7 @@ jobs: os: ubuntu20.04-8cores-32GB pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated runs-on: ${{ matrix.product.os }} - name: ETH Smoke Tests ${{ matrix.product.name }} + name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} steps: - name: Checkout the repo uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 @@ -311,6 +315,92 @@ jobs: else echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" fi + - name: Check for "enable tracing" label + id: check-label + run: | + label=$(jq -r '.pull_request.labels[]?.name // empty' "$GITHUB_EVENT_PATH") + + if [[ -n "$label" ]]; then + if [[ "$label" == "enable tracing" ]]; then + echo "Enable tracing label found." + echo "trace=true" >> $GITHUB_OUTPUT + else + echo "Enable tracing label not found." + echo "trace=false" >> $GITHUB_OUTPUT + fi + else + echo "No labels present or labels are null." + echo "trace=false" >> $GITHUB_OUTPUT + fi + + - name: Setup Grafana and OpenTelemetry + id: docker-setup + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + run: | + # Create network + docker network create --driver bridge tracing + + # Start Grafana + cd ./.github/tracing + docker run -d --network=tracing --name=grafana -p 3000:3000 -v $PWD/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml -e GF_AUTH_ANONYMOUS_ENABLED=true -e GF_AUTH_ANONYMOUS_ORG_ROLE=Admin -e GF_AUTH_DISABLE_LOGIN_FORM=true -e GF_FEATURE_TOGGLES_ENABLE=traceqlEditor grafana/grafana:9.4.3 + + # Start Tempo + docker run -d --network=tracing --name=tempo -v ./tempo.yaml:/etc/tempo.yaml -v $PWD/tempo-data:/tmp/tempo grafana/tempo:latest -config.file=/etc/tempo.yaml + + # Start OpenTelemetry Collector + docker run -d --network=tracing --name=otel-collector -v $PWD/otel-collector.yaml:/etc/otel-collector.yaml -p 4317:4317 otel/opentelemetry-collector:0.61.0 --config=/etc/otel-collector.yaml + + - name: Generate port + id: generate-port + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + env: + GITHUB_PR_NUMBER: ${{ github.event.number }} + run: | + PORT_BASE=3001 + MAX_PORT=8000 + + # Use PR number as offset. Given GitHub PRs are incremental, this guarantees uniqueness for at least 5000 PRs. + OFFSET=$GITHUB_PR_NUMBER + echo "PR Number: $OFFSET" + + # Ensure that we don't exceed the max port + if (( OFFSET > (MAX_PORT - PORT_BASE) )); then + OFFSET=$((OFFSET % (MAX_PORT - PORT_BASE))) + fi + + # Map the offset to the port range + REMOTE_PORT=$((PORT_BASE + OFFSET)) + echo "REMOTE_PORT=$REMOTE_PORT" >> $GITHUB_OUTPUT + - name: Reverse SSH Tunneling + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + env: + TRACING_SSH_KEY: ${{ secrets.TRACING_SSH_KEY }} + TRACING_SSH_SERVER: ${{ secrets.TRACING_SSH_SERVER }} + REMOTE_PORT: ${{ steps.generate-port.outputs.REMOTE_PORT }} + run: | + eval $(ssh-agent) + echo "test" + echo "$TRACING_SSH_KEY" | wc -c + echo "$TRACING_SSH_KEY" | tr -d '\r' | wc -c + echo "$TRACING_SSH_KEY" | tr -d '\r' | base64 --decode | ssh-add - + # f: background process + # N: do not execute a remote command + # R: remote port forwarding + ssh -o StrictHostKeyChecking=no -f -N -R $REMOTE_PORT:127.0.0.1:3000 user-gha@$TRACING_SSH_SERVER + echo "To view Grafana locally:" + echo "ssh -N -L 8000:localhost:$REMOTE_PORT user-gha@$TRACING_SSH_SERVER" + echo "Then visit http://localhost:8000 in a browser." + echo "If you are unable to connect, check with the security team that you have access to the tracing server." + - name: Show Grafana Logs + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + run: | + docker logs grafana + docker logs tempo + docker logs otel-collector + - name: Set sleep time to use in future steps + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + run: | + echo "SLEEP_TIME=2400" >> "$GITHUB_ENV" ## Run this step when changes that require tests to be run are made - name: Run Tests if: needs.changes.outputs.src == 'true' @@ -323,7 +413,7 @@ jobs: test_command_to_run: make test_need_operator_assets && cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} + cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: ${{ matrix.product.name }}-test-logs artifacts_location: ./integration-tests/smoke/logs/ @@ -347,17 +437,21 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ETH Smoke Tests ${{ matrix.product.name }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true + - name: Keep action running to view traces + if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' + run: | + echo "Sleeping for $SLEEP_TIME seconds..." + sleep $SLEEP_TIME ### Used to check the required checks box when the matrix completes eth-smoke-tests: @@ -368,15 +462,18 @@ jobs: steps: - name: Check smoke test matrix status if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-automation.result != 'success' - run: exit 1 + run: | + echo "${{ needs.eth-smoke-tests-matrix.result }}" + exit 1 - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ETH Smoke Tests + matrix-aggregator-status: ${{ needs.eth-smoke-tests-matrix.result }} continue-on-error: true cleanup: @@ -399,7 +496,7 @@ jobs: - name: Collect Metrics if: ${{ github.event_name == 'pull_request' }} id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -449,8 +546,8 @@ jobs: CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink - TEST_UPGRADE_VERSION: ${{ github.sha }} - TEST_UPGRADE_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + UPGRADE_VERSION: ${{ github.sha }} + UPGRADE_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink TEST_LOG_LEVEL: debug TEST_SUITE: migration steps: @@ -494,7 +591,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -600,7 +697,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -639,7 +736,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -663,7 +760,7 @@ jobs: - run: echo "this exists so we don't have to run anything else if the build is skipped" if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' - solana-smoke-tests: + solana-smoke-tests-matrix: if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: @@ -674,12 +771,12 @@ jobs: strategy: matrix: image: - - name: "" + - name: (legacy) tag-suffix: "" - name: (plugins) tag-suffix: -plugins name: Solana Smoke Tests ${{ matrix.image.name }} - runs-on: ubuntu-latest + runs-on: ubuntu20.04-16cores-64GB needs: [ build-chainlink, @@ -697,7 +794,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.src == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -709,6 +806,33 @@ jobs: with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} + - name: Run Setup + if: needs.changes.outputs.src == 'true' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + with: + go_mod_path: ./integration-tests/go.mod + cache_restore_only: true + cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Pull Artfacts + if: needs.changes.outputs.src == 'true' + run: | + IMAGE_NAME=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} + # Pull the Docker image + docker pull "$IMAGE_NAME" + + # Create a container without starting it + CONTAINER_ID=$(docker create "$IMAGE_NAME") + + # Copy the artifacts from the container + mkdir -p ./${{env.CONTRACT_ARTIFACTS_PATH}}/ + docker cp "$CONTAINER_ID:/go/testdir/${{env.CONTRACT_ARTIFACTS_PATH}}/" "./${{env.CONTRACT_ARTIFACTS_PATH}}/../" + + # Remove the created container + docker rm "$CONTAINER_ID" - name: Run Tests if: needs.changes.outputs.src == 'true' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 @@ -721,9 +845,11 @@ jobs: go_mod_path: ./integration-tests/go.mod cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + run_setup: false - name: Upload test log uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 if: failure() @@ -732,6 +858,27 @@ jobs: path: /tmp/gotest.log retention-days: 7 continue-on-error: true + + ### Used to check the required checks box when the matrix completes + solana-smoke-tests: + if: always() + runs-on: ubuntu-latest + name: Solana Smoke Tests + needs: [solana-smoke-tests-matrix] + steps: + - name: Check smoke test matrix status + if: needs.solana-smoke-tests-matrix.result != 'success' + run: exit 1 + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Solana Smoke Tests + matrix-aggregator-status: ${{ needs.solana-smoke-tests-matrix.result }} + continue-on-error: true ### End Solana Section ### Start Live Testnet Section @@ -797,7 +944,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/lint-gh-workflows.yml b/.github/workflows/lint-gh-workflows.yml index 66c69420606..1220f3a745f 100644 --- a/.github/workflows/lint-gh-workflows.yml +++ b/.github/workflows/lint-gh-workflows.yml @@ -9,11 +9,11 @@ jobs: - name: Check out Code uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Run actionlint - uses: reviewdog/action-actionlint@17ea0452ae2cd009a22ca629732a9ce7f49a55e6 # v1.39.0 + uses: reviewdog/action-actionlint@82693e9e3b239f213108d6e412506f8b54003586 # v1.39.1 - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 08e37d9c8eb..cd141142268 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -10,6 +10,8 @@ on: - "GOERLI" - "OPTIMISM_GOERLI" - "ARBITRUM_GOERLI" + - "ARBITRUM_SEPOLIA" + - "ARBITRUM_MAINNET" - "CELO_ALFAJORES" - "CELO_MAINNET" - "BASE_GOERLI" @@ -17,7 +19,11 @@ on: - "BSC_MAINNET" - "BSC_TESTNET" - "SCROLL_SEPOLIA" - - "SCROLL_MAINNET" + - "SCROLL_MAINNET" + - "MUMBAI" + - "POLYGON_MAINNET" + - "LINEA_GOERLI" + - "LINEA_MAINNET" fundingPrivateKey: description: Private funding key (Skip for Simulated) required: false @@ -81,7 +87,7 @@ jobs: steps: - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/on-demand-vrfv2plus-load-test.yml b/.github/workflows/on-demand-vrfv2plus-load-test.yml new file mode 100644 index 00000000000..f4ca096d5ce --- /dev/null +++ b/.github/workflows/on-demand-vrfv2plus-load-test.yml @@ -0,0 +1,126 @@ +name: On Demand VRFV2 Plus Load Test +on: + workflow_dispatch: + inputs: + network: + description: Network to run tests on + type: choice + options: + - "ETHEREUM_MAINNET" + - "SIMULATED" + - "SEPOLIA" + - "OPTIMISM_MAINNET" + - "OPTIMISM_GOERLI" + - "ARBITRUM_MAINNET" + - "ARBITRUM_GOERLI" + - "BSC_MAINNET" + - "BSC_TESTNET" + - "POLYGON_MAINNET" + - "MUMBAI" + - "AVALANCHE_FUJI" + - "AVALANCHE_MAINNET" + fundingPrivateKey: + description: Private funding key (Skip for Simulated) + required: false + type: string + wsURL: + description: WS URL for the network (Skip for Simulated) + required: false + type: string + httpURL: + description: HTTP URL for the network (Skip for Simulated) + required: false + type: string + chainlinkImage: + description: Container image location for the Chainlink nodes + required: true + default: public.ecr.aws/chainlink/chainlink + chainlinkVersion: + description: Container image version for the Chainlink nodes + required: true + default: "2.6.0" + performanceTestType: + description: Performance Test Type of test to run + type: choice + options: + - "Soak" + - "Load" + - "Stress" + - "Spike" + testDuration: + description: Duration of the test (time string) + required: false + default: 1m + useExistingEnv: + description: Set `true` to use existing environment or `false` to deploy CL node and all contracts + required: false + default: false + configBase64: + description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) + required: false +jobs: + vrfv2plus_load_test: + name: ${{ inputs.network }} VRFV2 Plus Load Test + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} + SELECTED_NETWORKS: ${{ inputs.network }} + TEST_TYPE: ${{ inputs.performanceTestType }} + VRFV2PLUS_TEST_DURATION: ${{ inputs.testDuration }} + VRFV2PLUS_USE_EXISTING_ENV: ${{ inputs.useExistingEnv }} + CONFIG: ${{ inputs.configBase64 }} + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + WASP_LOG_LEVEL: info + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ${{ inputs.network }} VRFV2 Plus Load Test + continue-on-error: true + - name: Get Inputs + run: | + EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) + EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) + EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) + + echo ::add-mask::$EVM_URLS + echo ::add-mask::$EVM_HTTP_URLS + echo ::add-mask::$EVM_KEYS + + echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV + echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV + echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@eccde1970eca69f079d3efb3409938a72ade8497 # v2.2.13 + with: + test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 6h -run TestVRFV2PlusLoad/vrfv2plus_soak_test ./load/vrfv2plus + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ inputs.chainlinkImage }} + cl_image_tag: ${{ inputs.chainlinkVersion }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/load/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} diff --git a/.github/workflows/operator-ui-cd.yml b/.github/workflows/operator-ui-cd.yml index 488e93778e6..4f6e82e07b3 100644 --- a/.github/workflows/operator-ui-cd.yml +++ b/.github/workflows/operator-ui-cd.yml @@ -50,7 +50,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml index 3297fa1d4bf..b79d8dfea24 100644 --- a/.github/workflows/performance-tests.yml +++ b/.github/workflows/performance-tests.yml @@ -42,7 +42,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -79,7 +79,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index d3788674d6d..e847216eb07 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Check for changed files id: changedfiles - uses: umani/changed-files@0239328a3a6268aad16af7c3e4efc78e32d6c0f0 # Version 4.0.1 + uses: umani/changed-files@d7f842d11479940a6036e3aacc6d35523e6ba978 # Version 4.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} pattern: '^(?!.*node_modules).*README\.md$' @@ -31,7 +31,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/sigscanner.yml b/.github/workflows/sigscanner.yml index 390af228f06..285a63cacbe 100644 --- a/.github/workflows/sigscanner.yml +++ b/.github/workflows/sigscanner.yml @@ -26,7 +26,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 8f0181640ea..590165c8e7a 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -30,6 +30,7 @@ jobs: tests: strategy: + fail-fast: false matrix: product: [vrf, automation, llo-feeds, functions, shared] needs: [changes] @@ -54,7 +55,7 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. - version: nightly-ca67d15f4abd46394b324c50e21e66f306a1162d + version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Run Forge build run: | @@ -85,7 +86,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index ac8240aa4e2..2e25e52753d 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -47,7 +47,7 @@ jobs: config: ./contracts/ci.json - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -89,7 +89,7 @@ jobs: path: ./contracts/coverage-${{ matrix.split.idx }}.json - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -144,7 +144,7 @@ jobs: run: pnpm test -- $SPLIT - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -169,7 +169,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml index 0e7ff30545d..b2537a5c9a7 100644 --- a/.github/workflows/solidity.yml +++ b/.github/workflows/solidity.yml @@ -40,7 +40,7 @@ jobs: run: pnpm prepublishOnly - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -84,7 +84,7 @@ jobs: run: gh pr comment -b 'Go solidity wrappers are out-of-date, regenerate them via the `make wrappers-all` command' - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -106,9 +106,11 @@ jobs: uses: ./.github/actions/setup-nodejs - name: Run pnpm lint run: pnpm lint + - name: Run solhint + run: pnpm solhint - name: Collect Metrics id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} @@ -134,7 +136,7 @@ jobs: - name: Collect Metrics if: needs.changes.outputs.changes == 'true' id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml index 49864f1cebe..97037652034 100644 --- a/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml +++ b/.github/workflows/sync-develop-from-smartcontractkit-chainlink.yml @@ -30,7 +30,7 @@ jobs: - name: Collect Metrics if: always() id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d2c2b7bdc9012651230b2608a1bcb0c48538b6ec + uses: smartcontractkit/push-gha-metrics-action@f4d2fcbe12e9e44921e0171d24085ab7d2a30bc9 # v2.0.1 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.gitignore b/.gitignore index 4d65eb32a1e..decea4a68a7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,7 @@ core/cmd/TestClient_ImportExportP2PKeyBundle_test_key.json output.txt race.* golangci-lint-output.txt -golangci-lint/ +/golangci-lint/ # DB state ./db/ diff --git a/.gitmodules b/.gitmodules index fe62399a72e..556d344c271 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "contracts/foundry-lib/forge-std"] path = contracts/foundry-lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "contracts/foundry-lib/openzeppelin-contracts"] - path = contracts/foundry-lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/.tool-versions b/.tool-versions index 9b2fa11518a..87910cf6d6f 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,7 +1,7 @@ golang 1.21.1 -mockery 2.28.1 +mockery 2.35.4 nodejs 16.16.0 postgres 13.3 helm 3.10.3 zig 0.10.1 -golangci-lint 1.54.2 +golangci-lint 1.55.0 diff --git a/CODEOWNERS b/CODEOWNERS index 2b2fb18443a..8ec42ed6dd4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,5 @@ # CODEOWNERS Best Practices -# 1. Per Github docs: "Order is important; the last matching pattern takes the most precedence." +# 1. Per Github docs: "Order is important; the last matching pattern takes the most precedence." # Please define less specific codeowner paths before more specific codeowner paths in order for the more specific rule to have priority # Misc @@ -37,6 +37,10 @@ # VRF-related services /core/services/vrf @smartcontractkit/vrf-team /core/services/blockhashstore @smartcontractkit/vrf-team +/core/services/blockheaderfeeder @smartcontractkit/vrf-team +/core/services/pipeline/task.vrf.go @smartcontractkit/vrf-team +/core/services/pipeline/task.vrfv2.go @smartcontractkit/vrf-team +/core/services/pipeline/task.vrfv2plus.go @smartcontractkit/vrf-team /core/services/ocr2/plugins/dkg @smartcontractkit/vrf-team /core/services/ocr2/plugins/ocr2vrf @smartcontractkit/vrf-team @@ -67,13 +71,25 @@ core/scripts/gateway @bolekk @pinebit /operator-ui/ @DeividasK @jkongie # Contracts -/contracts/ @se3000 @connorwstein -/contracts/**/*Keeper* @smartcontractkit/keepers -/contracts/**/*Upkeep* @smartcontractkit/keepers -/contracts/**/*Functions* @smartcontractkit/functions +/contracts/ @se3000 @connorwstein @RensR + +/contracts/srv/v0.8/automation @smartcontractkit/keepers +/contracts/**/*keeper* @smartcontractkit/keepers +/contracts/**/*upkeep* @smartcontractkit/keepers +/contracts/**/*automation* @smartcontractkit/keepers +/contracts/gas-snapshots/automation.gas-snapshot @smartcontractkit/keepers + /contracts/src/v0.8/functions @smartcontractkit/functions -contracts/test/v0.8/functions @smartcontractkit/functions +/contracts/**/*functions* @smartcontractkit/functions +/contracts/gas-snapshots/functions.gas-snapshot @smartcontractkit/functions + /contracts/src/v0.8/llo-feeds @austinborn @Fletch153 +/contracts/gas-snapshots/llo-feeds.gas-snapshot @austinborn @Fletch153 + +/contracts/src/v0.8/vrf @smartcontractkit/vrf-team +/contracts/**/*vrf* @smartcontractkit/vrf-team + +/contracts/src/v0.8/l2ep @simsonraj # Tests /integration-tests/ @smartcontractkit/test-tooling-team @@ -86,6 +102,8 @@ contracts/test/v0.8/functions @smartcontractkit/functions /.github/workflows/integration-chaos-tests.yml @smartcontractkit/test-tooling-team /.github/workflows/integration-tests-publish.yml @smartcontractkit/test-tooling-team /.github/workflows/performance-tests.yml @smartcontractkit/test-tooling-team +/.github/workflows/automation-ondemand-tests.yml @smartcontractkit/keepers +/.github/workflows/automation-benchmark-tests.yml @smartcontractkit/keepers /core/chainlink.Dockerfile @smartcontractkit/prodsec-public diff --git a/GNUmakefile b/GNUmakefile index 71279f43651..957df96ce45 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -51,24 +51,16 @@ chainlink-dev: operator-ui ## Build a dev build of chainlink binary. go build -tags dev $(GOFLAGS) . chainlink-test: operator-ui ## Build a test build of chainlink binary. - go build -tags test $(GOFLAGS) . + go build $(GOFLAGS) . .PHONY: chainlink-local-start chainlink-local-start: ./chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials -.PHONY: install-solana -install-solana: ## Build & install the chainlink-solana binary. - go install $(GOFLAGS) ./plugins/cmd/chainlink-solana - .PHONY: install-median install-median: ## Build & install the chainlink-median binary. go install $(GOFLAGS) ./plugins/cmd/chainlink-median -.PHONY: install-starknet -install-starknet: ## Build & install the chainlink-solana binary. - go install $(GOFLAGS) ./plugins/cmd/chainlink-starknet - .PHONY: docker ## Build the chainlink docker image docker: docker buildx build \ @@ -105,11 +97,11 @@ testscripts-update: ## Update testdata/scripts/* files via testscript. .PHONY: testdb testdb: ## Prepares the test database. - go run -tags test . local db preparetest + go run . local db preparetest .PHONY: testdb testdb-user-only: ## Prepares the test database with user only. - go run -tags test . local db preparetest --user-only + go run . local db preparetest --user-only # Format for CI .PHONY: presubmit @@ -120,7 +112,7 @@ presubmit: ## Format go files and imports. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.28.1 + go install github.com/vektra/mockery/v2@v2.35.4 .PHONY: codecgen codecgen: $(codecgen) ## Install codecgen @@ -146,7 +138,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.54.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.55.0 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/README.md b/README.md index f8dd24ffcc2..eff798d46b8 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ If you do end up modifying the migrations for the database, you will need to rer 7. Run tests: ```bash -go test -tags test ./... +go test ./... ``` #### Notes diff --git a/VERSION b/VERSION index 437459cd94c..24ba9a38de6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5.0 +2.7.0 diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 704c71cf79b..17d50ef5628 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -80,7 +80,7 @@ func (hb *HeadBroadcaster[H, BLOCK_HASH]) Name() string { } func (hb *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { - return map[string]error{hb.Name(): hb.StartStopOnce.Healthy()} + return map[string]error{hb.Name(): hb.Healthy()} } func (hb *HeadBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(head H) { diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index 24c221d61ab..ee4969497a8 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -83,9 +83,8 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(handleNewHead } else if err != nil { hl.logger.Errorw("Error in new head subscription, unsubscribed", "err", err) continue - } else { - break } + break } } diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 91813d89a2d..1978b281d44 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -9,7 +9,8 @@ import ( "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "golang.org/x/exp/maps" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" @@ -154,10 +155,8 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Name() string { } func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error { - report := map[string]error{ - ht.Name(): ht.StartStopOnce.Healthy(), - } - maps.Copy(report, ht.headListener.HealthReport()) + report := map[string]error{ht.Name(): ht.Healthy()} + services.CopyHealth(report, ht.headListener.HealthReport()) return report } diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index ac83705208b..edda18d57e8 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -156,13 +156,12 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) IsValid() bool { return r0 } -type mockConstructorTestingTNewHead interface { +// NewHead creates a new instance of Head. 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 NewHead[BLOCK_HASH types.Hashable, CHAIN_ID types.ID](t interface { mock.TestingT Cleanup(func()) -} - -// NewHead creates a new instance of Head. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHead[BLOCK_HASH types.Hashable, CHAIN_ID types.ID](t mockConstructorTestingTNewHead) *Head[BLOCK_HASH, CHAIN_ID] { +}) *Head[BLOCK_HASH, CHAIN_ID] { mock := &Head[BLOCK_HASH, CHAIN_ID]{} mock.Mock.Test(t) diff --git a/common/mocks/head_broadcaster.go b/common/mocks/head_broadcaster.go index c7018744254..12036f67843 100644 --- a/common/mocks/head_broadcaster.go +++ b/common/mocks/head_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -117,13 +117,12 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable return r0, r1 } -type mockConstructorTestingTNewHeadBroadcaster interface { +// NewHeadBroadcaster creates a new instance of HeadBroadcaster. 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 NewHeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t interface { mock.TestingT Cleanup(func()) -} - -// NewHeadBroadcaster creates a new instance of HeadBroadcaster. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t mockConstructorTestingTNewHeadBroadcaster) *HeadBroadcaster[H, BLOCK_HASH] { +}) *HeadBroadcaster[H, BLOCK_HASH] { mock := &HeadBroadcaster[H, BLOCK_HASH]{} mock.Mock.Test(t) diff --git a/common/mocks/head_tracker.go b/common/mocks/head_tracker.go index b6783bf5e55..2a1f64eeeb7 100644 --- a/common/mocks/head_tracker.go +++ b/common/mocks/head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -114,13 +114,12 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewHeadTracker interface { +// NewHeadTracker creates a new instance of HeadTracker. 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 NewHeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t interface { mock.TestingT Cleanup(func()) -} - -// NewHeadTracker creates a new instance of HeadTracker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t mockConstructorTestingTNewHeadTracker) *HeadTracker[H, BLOCK_HASH] { +}) *HeadTracker[H, BLOCK_HASH] { mock := &HeadTracker[H, BLOCK_HASH]{} mock.Mock.Test(t) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index f00fe6d850c..6512f67fe0b 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -109,7 +109,7 @@ type Broadcaster[ txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH] + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] resumeCallback ResumeCallback chainID CHAIN_ID config txmgrtypes.BroadcasterChainConfig @@ -143,6 +143,10 @@ type Broadcaster[ utils.StartStopOnce parseAddr func(string) (ADDR, error) + + sequenceLock sync.RWMutex + nextSequenceMap map[ADDR]SEQ + generateNextSequence types.GenerateNextSequenceFunc[SEQ] } func NewBroadcaster[ @@ -163,11 +167,12 @@ func NewBroadcaster[ keystore txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ], eventBroadcaster pg.EventBroadcaster, txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH], + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], logger logger.Logger, checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], autoSyncSequence bool, parseAddress func(string) (ADDR, error), + generateNextSequence types.GenerateNextSequenceFunc[SEQ], ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { logger = logger.Named("Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ @@ -189,6 +194,7 @@ func NewBroadcaster[ } b.processUnstartedTxsImpl = b.processUnstartedTxs + b.generateNextSequence = generateNextSequence return b } @@ -235,6 +241,13 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star eb.wg.Add(1) go eb.txInsertTriggerer() + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap, err = eb.loadNextSequenceMap(eb.enabledAddresses) + if err != nil { + return errors.Wrap(err, "Broadcaster: failed to load next sequence map") + } + eb.isStarted = true return nil } @@ -270,7 +283,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { - return map[string]error{eb.Name(): eb.StartStopOnce.Healthy()} + return map[string]error{eb.Name(): eb.Healthy()} } // Trigger forces the monitor for a particular address to recheck for new txes @@ -312,6 +325,33 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) txIn } } +// Load the next sequence map using the tx table or on-chain (if not found in tx table) +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) loadNextSequenceMap(addresses []ADDR) (map[ADDR]SEQ, error) { + ctx, cancel := eb.chStop.NewCtx() + defer cancel() + + nextSequenceMap := make(map[ADDR]SEQ) + for _, address := range addresses { + // Get the highest sequence from the tx table + // Will need to be incremented since this sequence is already used + seq, err := eb.txStore.FindLatestSequence(ctx, address, eb.chainID) + if err != nil { + // Look for nonce on-chain if no tx found for address in TxStore or if error occurred + // Returns the nonce that should be used for the next transaction so no need to increment + seq, err = eb.client.PendingSequenceAt(ctx, address) + if err != nil { + return nil, errors.New("failed to retrieve next sequence from on-chain causing failure to load next sequence map on broadcaster startup") + } + + nextSequenceMap[address] = seq + } else { + nextSequenceMap[address] = eb.generateNextSequence(seq) + } + } + + return nextSequenceMap, nil +} + func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) newSequenceSyncBackoff() backoff.Backoff { return backoff.Backoff{ Min: 100 * time.Millisecond, @@ -389,31 +429,42 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) moni } } -// syncSequence tries to sync the key sequence, retrying indefinitely until success +// syncSequence tries to sync the key sequence, retrying indefinitely until success or stop signal is sent func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SyncSequence(ctx context.Context, addr ADDR) { sequenceSyncRetryBackoff := eb.newSequenceSyncBackoff() - if err := eb.sequenceSyncer.Sync(ctx, addr); err != nil { - // Enter retry loop with backoff - var attempt int - eb.logger.Errorw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - for { - select { - case <-eb.chStop: - return - case <-time.After(sequenceSyncRetryBackoff.Duration()): - attempt++ - - if err := eb.sequenceSyncer.Sync(ctx, addr); err != nil { - if attempt > 5 { - eb.logger.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - eb.SvcErrBuffer.Append(err) - } else { - eb.logger.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) - } - continue + localSequence, err := eb.GetNextSequence(addr) + // Address not found in map so skip sync + if err != nil { + eb.logger.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + return + } + + // Enter loop with retries + var attempt int + for { + select { + case <-eb.chStop: + return + case <-time.After(sequenceSyncRetryBackoff.Duration()): + attempt++ + newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) + if err != nil { + if attempt > 5 { + eb.logger.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + eb.SvcErrBuffer.Append(err) + } else { + eb.logger.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) } - return + continue } + // Found new sequence to use from on-chain + if localSequence.String() != newNextSequence.String() { + eb.logger.Infow("Fast-forward sequence", "address", addr, "newNextSequence", newNextSequence, "oldNextSequence", localSequence) + // Set new sequence in the map + eb.SetNextSequence(addr, newNextSequence) + } + return + } } } @@ -444,12 +495,12 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc for { maxInFlightTransactions := eb.txConfig.MaxInFlight() if maxInFlightTransactions > 0 { - nUnconfirmed, err := eb.txStore.CountUnconfirmedTransactions(fromAddress, eb.chainID) + nUnconfirmed, err := eb.txStore.CountUnconfirmedTransactions(ctx, fromAddress, eb.chainID) if err != nil { return true, errors.Wrap(err, "CountUnconfirmedTransactions failed") } if nUnconfirmed >= maxInFlightTransactions { - nUnstarted, err := eb.txStore.CountUnstartedTransactions(fromAddress, eb.chainID) + nUnstarted, err := eb.txStore.CountUnstartedTransactions(ctx, fromAddress, eb.chainID) if err != nil { return true, errors.Wrap(err, "CountUnstartedTransactions failed") } @@ -477,7 +528,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc return retryable, errors.Wrap(err, "processUnstartedTxs failed on NewAttempt") } - if err := eb.txStore.UpdateTxUnstartedToInProgress(etx, &a); errors.Is(err, ErrTxRemoved) { + if err := eb.txStore.UpdateTxUnstartedToInProgress(ctx, etx, &a); errors.Is(err, ErrTxRemoved) { eb.logger.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) continue } else if err != nil { @@ -493,7 +544,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc // handleInProgressTx checks if there is any transaction // in_progress and if so, finishes the job func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleAnyInProgressTx(ctx context.Context, fromAddress ADDR) (err error, retryable bool) { - etx, err := eb.txStore.GetTxInProgress(fromAddress) + etx, err := eb.txStore.GetTxInProgress(ctx, fromAddress) if err != nil { return errors.Wrap(err, "handleAnyInProgressTx failed"), true } @@ -505,16 +556,6 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand return nil, false } -// This function is used to pass the queryer from the txmgr to the keystore. -// It is inevitable we have to pass the queryer because we need the keystate's next sequence to be incremented -// atomically alongside the transition from `in_progress` to `broadcast` so it is ready for the next transaction -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) incrementNextSequenceAtomic(tx pg.Queryer, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { - if err := eb.incrementNextSequence(etx.FromAddress, *etx.Sequence, pg.WithQueryer(tx)); err != nil { - return errors.Wrap(err, "saveUnconfirmed failed") - } - return nil -} - // There can be at most one in_progress transaction per address. // Here we complete the job that we didn't finish last time. func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) { @@ -603,9 +644,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // and hand off to the confirmer to get the receipt (or mark as // failed). observeTimeUntilBroadcast(eb.chainID, etx.CreatedAt, time.Now()) - return eb.txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(tx pg.Queryer) error { - return eb.incrementNextSequenceAtomic(tx, etx) - }), true + // Check if from_address exists in map to ensure it is valid before broadcasting + var sequence SEQ + sequence, err = eb.GetNextSequence(etx.FromAddress) + if err != nil { + return err, true + } + err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) + if err != nil { + return err, true + } + // Increment sequence if successfully broadcasted + eb.IncrementNextSequence(etx.FromAddress, sequence) + return err, true case clienttypes.Underpriced: return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt) case clienttypes.InsufficientFunds: @@ -650,9 +701,20 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Despite the error, the RPC node considers the previously sent // transaction to have been accepted. In this case, the right thing to // do is assume success and hand off to Confirmer - return eb.txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(tx pg.Queryer) error { - return eb.incrementNextSequenceAtomic(tx, etx) - }), true + + // Check if from_address exists in map to ensure it is valid before broadcasting + var sequence SEQ + sequence, err = eb.GetNextSequence(etx.FromAddress) + if err != nil { + return err, true + } + err = eb.txStore.UpdateTxAttemptInProgressToBroadcast(ctx, &etx, attempt, txmgrtypes.TxAttemptBroadcast) + if err != nil { + return err, true + } + // Increment sequence if successfully broadcasted + eb.IncrementNextSequence(etx.FromAddress, sequence) + return err, true } // Either the unknown error prevented the transaction from being mined, or // it has not yet propagated to the mempool, or there is some race on the @@ -668,8 +730,10 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // Finds next transaction in the queue, assigns a sequence, and moves it to "in_progress" state ready for broadcast. // Returns nil if no transactions are in queue func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) nextUnstartedTransactionWithSequence(fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ctx, cancel := eb.chStop.NewCtx() + defer cancel() etx := &txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{} - if err := eb.txStore.FindNextUnstartedTransactionFromAddress(etx, fromAddress, eb.chainID); err != nil { + if err := eb.txStore.FindNextUnstartedTransactionFromAddress(ctx, etx, fromAddress, eb.chainID); err != nil { if errors.Is(err, sql.ErrNoRows) { // Finish. No more transactions left to process. Hoorah! return nil, nil @@ -677,7 +741,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next return nil, errors.Wrap(err, "findNextUnstartedTransactionFromAddress failed") } - sequence, err := eb.getNextSequence(etx.FromAddress) + sequence, err := eb.GetNextSequence(etx.FromAddress) if err != nil { return nil, err } @@ -722,7 +786,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveTryAgainAttempt(ctx context.Context, lgr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, newFee FEE, newFeeLimit uint32) (err error, retyrable bool) { - if err = eb.txStore.SaveReplacementInProgressAttempt(attempt, &replacementAttempt); err != nil { + if err = eb.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { return errors.Wrap(err, "tryAgainWithNewFee failed"), true } lgr.Debugw("Bumped fee on initial send", "oldFee", attempt.TxFee.String(), "newFee", newFee.String(), "newFeeLimit", newFeeLimit) @@ -730,6 +794,8 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save } func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveFatallyErroredTransaction(lgr logger.Logger, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ctx, cancel := eb.chStop.NewCtx() + defer cancel() if etx.State != TxInProgress { return errors.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) } @@ -756,15 +822,33 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save return errors.Wrap(err, "failed to resume pipeline") } } - return eb.txStore.UpdateTxFatalError(etx) + return eb.txStore.UpdateTxFatalError(ctx, etx) +} + +// Used to get the next usable sequence for a transaction +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetNextSequence(address ADDR) (seq SEQ, err error) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + // Get next sequence from map + seq, exists := eb.nextSequenceMap[address] + if !exists { + return seq, errors.New(fmt.Sprint("address not found in next sequence map: ", address)) + } + return seq, nil } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getNextSequence(address ADDR) (sequence SEQ, err error) { - return eb.ks.NextSequence(address, eb.chainID) +// Used to increment the sequence in the mapping to have the next usable one available for the next transaction +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) IncrementNextSequence(address ADDR, seq SEQ) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap[address] = eb.generateNextSequence(seq) } -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) incrementNextSequence(address ADDR, currentSequence SEQ, qopts ...pg.QOpt) error { - return eb.ks.IncrementNextSequence(address, eb.chainID, currentSequence, qopts...) +// Used to set the next sequence explicitly to a certain value +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SetNextSequence(address ADDR, seq SEQ) { + eb.sequenceLock.Lock() + defer eb.sequenceLock.Unlock() + eb.nextSequenceMap[address] = seq } func observeTimeUntilBroadcast[CHAIN_ID types.ID](chainID CHAIN_ID, createdAt, broadcastAt time.Time) { diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index dbd67693aa3..31bba771410 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -21,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/label" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -239,7 +238,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Nam } func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HealthReport() map[string]error { - return map[string]error{ec.Name(): ec.StartStopOnce.Healthy()} + return map[string]error{ec.Name(): ec.Healthy()} } func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() { @@ -279,7 +278,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro ec.lggr.Debugw("processHead start", "headNum", head.BlockNumber(), "id", "confirmer") - if err := ec.txStore.SetBroadcastBeforeBlockNum(head.BlockNumber(), ec.chainID); err != nil { + if err := ec.txStore.SetBroadcastBeforeBlockNum(ctx, head.BlockNumber(), ec.chainID); err != nil { return errors.Wrap(err, "SetBroadcastBeforeBlockNum failed") } if err := ec.CheckConfirmedMissingReceipt(ctx); err != nil { @@ -340,7 +339,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro // // This scenario might sound unlikely but has been observed to happen multiple times in the wild on Polygon. func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckConfirmedMissingReceipt(ctx context.Context) (err error) { - attempts, err := ec.txStore.FindTxAttemptsConfirmedMissingReceipt(ec.chainID) + attempts, err := ec.txStore.FindTxAttemptsConfirmedMissingReceipt(ctx, ec.chainID) if err != nil { return err } @@ -351,7 +350,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che txCodes, txErrs, broadcastTime, txIDs, err := ec.client.BatchSendTransactions(ctx, attempts, int(ec.chainConfig.RPCDefaultBatchSize()), ec.lggr) // update broadcast times before checking additional errors if len(txIDs) > 0 { - if updateErr := ec.txStore.UpdateBroadcastAts(broadcastTime, txIDs); updateErr != nil { + if updateErr := ec.txStore.UpdateBroadcastAts(ctx, broadcastTime, txIDs); updateErr != nil { err = fmt.Errorf("%w: failed to update broadcast time: %w", err, updateErr) } } @@ -369,7 +368,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che txIDsToUnconfirm = append(txIDsToUnconfirm, attempts[idx].TxID) } - err = ec.txStore.UpdateTxsUnconfirmed(txIDsToUnconfirm) + err = ec.txStore.UpdateTxsUnconfirmed(ctx, txIDsToUnconfirm) if err != nil { return err @@ -379,7 +378,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che // CheckForReceipts finds attempts that are still pending and checks to see if a receipt is present for the given block number func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckForReceipts(ctx context.Context, blockNum int64) error { - attempts, err := ec.txStore.FindTxAttemptsRequiringReceiptFetch(ec.chainID) + attempts, err := ec.txStore.FindTxAttemptsRequiringReceiptFetch(ctx, ec.chainID) if err != nil { return errors.Wrap(err, "FindTxAttemptsRequiringReceiptFetch failed") } @@ -421,11 +420,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che } } - if err := ec.txStore.MarkAllConfirmedMissingReceipt(ec.chainID); err != nil { + if err := ec.txStore.MarkAllConfirmedMissingReceipt(ctx, ec.chainID); err != nil { return errors.Wrap(err, "unable to mark txes as 'confirmed_missing_receipt'") } - if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(blockNum, ec.chainConfig.FinalityDepth(), ec.chainID); err != nil { + if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(ctx, blockNum, ec.chainConfig.FinalityDepth(), ec.chainID); err != nil { return errors.Wrap(err, "unable to confirm buried unconfirmed txes") } return nil @@ -489,7 +488,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) fet if err != nil { return errors.Wrap(err, "batchFetchReceipts failed") } - if err := ec.txStore.SaveFetchedReceipts(receipts, ec.chainID); err != nil { + if err := ec.txStore.SaveFetchedReceipts(ctx, receipts, ec.chainID); err != nil { return errors.Wrap(err, "saveFetchedReceipts failed") } promNumConfirmedTxs.WithLabelValues(ec.chainID.String()).Add(float64(len(receipts))) @@ -511,7 +510,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) get func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) batchFetchReceipts(ctx context.Context, attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockNum int64) (receipts []R, err error) { // Metadata is required to determine whether a tx is forwarded or not. if ec.txConfig.ForwardersEnabled() { - err = ec.txStore.PreloadTxes(attempts) + err = ec.txStore.PreloadTxes(ctx, attempts) if err != nil { return nil, errors.Wrap(err, "Confirmer#batchFetchReceipts error loading txs for attempts") } @@ -648,7 +647,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) reb lggr.Debugw("Rebroadcasting transaction", "nPreviousAttempts", len(etx.TxAttempts), "fee", attempt.TxFee) - if err := ec.txStore.SaveInProgressAttempt(&attempt); err != nil { + if err := ec.txStore.SaveInProgressAttempt(ctx, &attempt); err != nil { return errors.Wrap(err, "saveInProgressAttempt failed") } @@ -687,7 +686,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringRebroadcast(ctx context.Context, lggr logger.Logger, address ADDR, blockNum, gasBumpThreshold, bumpDepth int64, maxInFlightTransactions uint32, chainID CHAIN_ID) (etxs []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { // NOTE: These two queries could be combined into one using union but it // becomes harder to read and difficult to test in isolation. KISS principle - etxInsufficientFunds, err := ec.txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(address, chainID, pg.WithParentCtx(ctx)) + etxInsufficientFunds, err := ec.txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(ctx, address, chainID) if err != nil { return nil, err } @@ -825,7 +824,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han ec.lggr.Warnw("Got terminally underpriced error for gas bump, this should never happen unless the remote RPC node changed its configuration on the fly, or you are using multiple RPC nodes with different minimum gas price requirements. This is not recommended", "err", sendError, "attempt", attempt) // "Lazily" load attempts here since the overwhelmingly common case is // that we don't need them unless we enter this path - if err := ec.txStore.LoadTxAttempts(&etx, pg.WithParentCtx(ctx)); err != nil { + if err := ec.txStore.LoadTxAttempts(ctx, &etx); err != nil { return errors.Wrap(err, "failed to load TxAttempts while bumping on terminally underpriced error") } if len(etx.TxAttempts) == 0 { @@ -850,7 +849,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han "replacementAttempt", replacementAttempt, ).Errorf("gas price was rejected by the node for being too low. Node returned: '%s'", sendError.Error()) - if err := ec.txStore.SaveReplacementInProgressAttempt(attempt, &replacementAttempt); err != nil { + if err := ec.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { return errors.Wrap(err, "saveReplacementInProgressAttempt failed") } return ec.handleInProgressAttempt(ctx, lggr, etx, replacementAttempt, blockHeight) @@ -882,11 +881,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han return ec.txStore.SaveConfirmedMissingReceiptAttempt(ctx, timeout, &attempt, now) case clienttypes.InsufficientFunds: timeout := ec.dbConfig.DefaultQueryTimeout() - return ec.txStore.SaveInsufficientFundsAttempt(timeout, &attempt, now) + return ec.txStore.SaveInsufficientFundsAttempt(ctx, timeout, &attempt, now) case clienttypes.Successful: lggr.Debugw("Successfully broadcast transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash.String()) timeout := ec.dbConfig.DefaultQueryTimeout() - return ec.txStore.SaveSentAttempt(timeout, &attempt, now) + return ec.txStore.SaveSentAttempt(ctx, timeout, &attempt, now) case clienttypes.Unknown: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough @@ -921,7 +920,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Ens } else { ec.nConsecutiveBlocksChainTooShort = 0 } - etxs, err := ec.txStore.FindTransactionsConfirmedInBlockRange(head.BlockNumber(), head.EarliestHeadInChain().BlockNumber(), ec.chainID) + etxs, err := ec.txStore.FindTransactionsConfirmedInBlockRange(ctx, head.BlockNumber(), head.EarliestHeadInChain().BlockNumber(), ec.chainID) if err != nil { return errors.Wrap(err, "findTransactionsConfirmedInBlockRange failed") } @@ -1015,7 +1014,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) mar ec.lggr.Infow(fmt.Sprintf("Re-org detected. Rebroadcasting transaction %s which may have been re-org'd out of the main chain", attempt.Hash.String()), logValues...) // Put it back in progress and delete all receipts (they do not apply to the new chain) - err := ec.txStore.UpdateTxForRebroadcast(etx, attempt) + err := ec.txStore.UpdateTxForRebroadcast(ec.ctx, etx, attempt) return errors.Wrap(err, "markForRebroadcast failed") } @@ -1034,7 +1033,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For for _, seq := range seqs { - etx, err := ec.txStore.FindTxWithSequence(address, seq) + etx, err := ec.txStore.FindTxWithSequence(context.TODO(), address, seq) if err != nil { return errors.Wrap(err, "ForceRebroadcast failed") } diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index ae878c18a02..c01f182c9bd 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -9,8 +9,6 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - txmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -37,30 +35,23 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close( return r0 } -// CreateTransaction provides a mock function with given fields: txRequest, qopts -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], qopts ...pg.QOpt) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, txRequest) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CreateTransaction provides a mock function with given fields: ctx, txRequest +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, txRequest) var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], ...pg.QOpt) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(txRequest, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, txRequest) } - if rf, ok := ret.Get(0).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], ...pg.QOpt) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(txRequest, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH]) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, txRequest) } else { r0 = ret.Get(0).(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], ...pg.QOpt) error); ok { - r1 = rf(txRequest, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH]) error); ok { + r1 = rf(ctx, txRequest) } else { r1 = ret.Error(1) } @@ -146,13 +137,13 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Regist _m.Called(fn) } -// Reset provides a mock function with given fields: f, addr, abandon -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(f func(), addr ADDR, abandon bool) error { - ret := _m.Called(f, addr, abandon) +// Reset provides a mock function with given fields: addr, abandon +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { + ret := _m.Called(addr, abandon) var r0 error - if rf, ok := ret.Get(0).(func(func(), ADDR, bool) error); ok { - r0 = rf(f, addr, abandon) + if rf, ok := ret.Get(0).(func(ADDR, bool) error); ok { + r0 = rf(addr, abandon) } else { r0 = ret.Error(0) } @@ -160,23 +151,23 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset( return r0 } -// SendNativeToken provides a mock function with given fields: chainID, from, to, value, gasLimit -func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(chainID, from, to, value, gasLimit) +// SendNativeToken provides a mock function with given fields: ctx, chainID, from, to, value, gasLimit +func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, chainID, from, to, value, gasLimit) var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(CHAIN_ID, ADDR, ADDR, big.Int, uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(chainID, from, to, value, gasLimit) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, chainID, from, to, value, gasLimit) } - if rf, ok := ret.Get(0).(func(CHAIN_ID, ADDR, ADDR, big.Int, uint32) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(chainID, from, to, value, gasLimit) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, chainID, from, to, value, gasLimit) } else { r0 = ret.Get(0).(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(CHAIN_ID, ADDR, ADDR, big.Int, uint32) error); ok { - r1 = rf(chainID, from, to, value, gasLimit) + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID, ADDR, ADDR, big.Int, uint32) error); ok { + r1 = rf(ctx, chainID, from, to, value, gasLimit) } else { r1 = ret.Error(1) } @@ -203,13 +194,12 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trigge _m.Called(addr) } -type mockConstructorTestingTNewTxManager interface { +// NewTxManager creates a new instance of TxManager. 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 NewTxManager[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence, FEE feetypes.Fee](t interface { mock.TestingT Cleanup(func()) -} - -// NewTxManager creates a new instance of TxManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTxManager[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence, FEE feetypes.Fee](t mockConstructorTestingTNewTxManager) *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { +}) *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { mock := &TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{} mock.Mock.Test(t) diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 5394266de42..96bc4860d71 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -97,6 +97,8 @@ func (r *Reaper[CHAIN_ID]) SetLatestBlockNum(latestBlockNum int64) { // ReapTxes deletes old txes func (r *Reaper[CHAIN_ID]) ReapTxes(headNum int64) error { + ctx, cancel := utils.StopChan(r.chStop).NewCtx() + defer cancel() threshold := r.txConfig.ReaperThreshold() if threshold == 0 { r.log.Debug("Transactions.ReaperThreshold set to 0; skipping ReapTxes") @@ -108,7 +110,7 @@ func (r *Reaper[CHAIN_ID]) ReapTxes(headNum int64) error { r.log.Debugw(fmt.Sprintf("reaping old txes created before %s", timeThreshold.Format(time.RFC3339)), "ageThreshold", threshold, "timeThreshold", timeThreshold, "minBlockNumberToKeep", minBlockNumberToKeep) - if err := r.store.ReapTxHistory(minBlockNumberToKeep, timeThreshold, r.chainID); err != nil { + if err := r.store.ReapTxHistory(ctx, minBlockNumberToKeep, timeThreshold, r.chainID); err != nil { return err } diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index 20652aaf837..655de0f1135 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -139,7 +139,7 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) resendUnconfi var allAttempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] for _, k := range enabledAddresses { var attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - attempts, err = er.txStore.FindTxAttemptsRequiringResend(olderThan, maxInFlightTransactions, er.chainID, k) + attempts, err = er.txStore.FindTxAttemptsRequiringResend(er.ctx, olderThan, maxInFlightTransactions, er.chainID, k) if err != nil { return fmt.Errorf("failed to FindTxAttemptsRequiringResend: %w", err) } @@ -163,7 +163,7 @@ func (er *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) resendUnconfi // update broadcast times before checking additional errors if len(txIDs) > 0 { - if updateErr := er.txStore.UpdateBroadcastAts(broadcastTime, txIDs); updateErr != nil { + if updateErr := er.txStore.UpdateBroadcastAts(er.ctx, broadcastTime, txIDs); updateErr != nil { err = errors.Join(err, fmt.Errorf("failed to update broadcast time: %w", updateErr)) } } diff --git a/common/txmgr/nonce_syncer.go b/common/txmgr/sequence_syncer.go similarity index 55% rename from common/txmgr/nonce_syncer.go rename to common/txmgr/sequence_syncer.go index 3c96473f800..dd4d458dd74 100644 --- a/common/txmgr/nonce_syncer.go +++ b/common/txmgr/sequence_syncer.go @@ -6,6 +6,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/types" ) -type SequenceSyncer[ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable] interface { - Sync(ctx context.Context, addr ADDR) (err error) +type SequenceSyncer[ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence] interface { + Sync(ctx context.Context, addr ADDR, localSequence SEQ) (SEQ, error) } diff --git a/common/txmgr/strategies.go b/common/txmgr/strategies.go index 72fc6ba44fe..b986d0d9b80 100644 --- a/common/txmgr/strategies.go +++ b/common/txmgr/strategies.go @@ -8,7 +8,6 @@ import ( "github.com/pkg/errors" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) var _ txmgrtypes.TxStrategy = SendEveryStrategy{} @@ -33,7 +32,7 @@ func NewSendEveryStrategy() txmgrtypes.TxStrategy { type SendEveryStrategy struct{} func (SendEveryStrategy) Subject() uuid.NullUUID { return uuid.NullUUID{} } -func (SendEveryStrategy) PruneQueue(pruneService txmgrtypes.UnstartedTxQueuePruner, qopt pg.QOpt) (int64, error) { +func (SendEveryStrategy) PruneQueue(ctx context.Context, pruneService txmgrtypes.UnstartedTxQueuePruner) (int64, error) { return 0, nil } @@ -57,11 +56,12 @@ func (s DropOldestStrategy) Subject() uuid.NullUUID { return uuid.NullUUID{UUID: s.subject, Valid: true} } -func (s DropOldestStrategy) PruneQueue(pruneService txmgrtypes.UnstartedTxQueuePruner, qopt pg.QOpt) (n int64, err error) { - ctx, cancel := context.WithTimeout(context.Background(), s.queryTimeout) - +func (s DropOldestStrategy) PruneQueue(ctx context.Context, pruneService txmgrtypes.UnstartedTxQueuePruner) (n int64, err error) { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, s.queryTimeout) defer cancel() - n, err = pruneService.PruneUnstartedTxQueue(s.queueSize, s.subject, pg.WithParentCtx(ctx), qopt) + + n, err = pruneService.PruneUnstartedTxQueue(ctx, s.queueSize, s.subject) if err != nil { return 0, errors.Wrap(err, "DropOldestStrategy#PruneQueue failed") } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index 0bcf3e482ee..980067b5fbf 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -3,21 +3,21 @@ package txmgr import ( "context" "database/sql" + "errors" "fmt" "math/big" "sync" "time" "github.com/google/uuid" - "github.com/pkg/errors" - "golang.org/x/exp/maps" + pkgerrors "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -41,13 +41,13 @@ type TxManager[ FEE feetypes.Fee, ] interface { types.HeadTrackable[HEAD, BLOCK_HASH] - services.ServiceCtx + services.Service Trigger(addr ADDR) - CreateTransaction(txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], qopts ...pg.QOpt) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error) RegisterResumeCallback(fn ResumeCallback) - SendNativeToken(chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - Reset(f func(), addr ADDR, abandon bool) error + SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + Reset(addr ADDR, abandon bool) error } type reset struct { @@ -93,7 +93,7 @@ type Txm[ confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] fwdMgr txmgrtypes.ForwarderManager[ADDR] txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH] + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ] } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RegisterResumeCallback(fn ResumeCallback) { @@ -122,7 +122,7 @@ func NewTxm[ fwdMgr txmgrtypes.ForwarderManager[ADDR], txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE], - sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH], + sequenceSyncer SequenceSyncer[ADDR, TX_HASH, BLOCK_HASH, SEQ], broadcaster *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], confirmer *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], resender *Resender[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], @@ -166,14 +166,14 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx return b.StartOnce("Txm", func() error { var ms services.MultiStart if err := ms.Start(ctx, b.broadcaster); err != nil { - return errors.Wrap(err, "Txm: Broadcaster failed to start") + return pkgerrors.Wrap(err, "Txm: Broadcaster failed to start") } if err := ms.Start(ctx, b.confirmer); err != nil { - return errors.Wrap(err, "Txm: Confirmer failed to start") + return pkgerrors.Wrap(err, "Txm: Confirmer failed to start") } if err := ms.Start(ctx, b.txAttemptBuilder); err != nil { - return errors.Wrap(err, "Txm: Estimator failed to start") + return pkgerrors.Wrap(err, "Txm: Estimator failed to start") } b.wg.Add(1) @@ -190,7 +190,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx if b.fwdMgr != nil { if err := ms.Start(ctx, b.fwdMgr); err != nil { - return errors.Wrap(err, "Txm: ForwarderManager failed to start") + return pkgerrors.Wrap(err, "Txm: ForwarderManager failed to start") } } @@ -198,13 +198,11 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx }) } -// Reset stops Broadcaster/Confirmer, executes callback, then starts them -// again -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(callback func(), addr ADDR, abandon bool) (err error) { +// Reset stops Broadcaster/Confirmer, executes callback, then starts them again +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr ADDR, abandon bool) (err error) { ok := b.IfStarted(func() { done := make(chan error) f := func() { - callback() if abandon { err = b.abandon(addr) } @@ -223,8 +221,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(call // - marks all pending and inflight transactions fatally errored (note: at this point all transactions are either confirmed or fatally errored) // this must not be run while Broadcaster or Confirmer are running func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) abandon(addr ADDR) (err error) { - err = b.txStore.Abandon(b.chainID, addr) - return errors.Wrapf(err, "abandon failed to update txes for key %s", addr.String()) + ctx, cancel := utils.StopChan(b.chStop).NewCtx() + defer cancel() + err = b.txStore.Abandon(ctx, b.chainID, addr) + return pkgerrors.Wrapf(err, "abandon failed to update txes for key %s", addr.String()) } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (merr error) { @@ -241,13 +241,15 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() (m } if b.fwdMgr != nil { if err := b.fwdMgr.Close(); err != nil { - return errors.Wrap(err, "Txm: failed to stop ForwarderManager") + merr = errors.Join(merr, pkgerrors.Wrap(err, "Txm: failed to stop ForwarderManager")) } } b.wg.Wait() - b.txAttemptBuilder.Close() + if err := b.txAttemptBuilder.Close(); err != nil { + merr = errors.Join(merr, pkgerrors.Wrap(err, "Txm: failed to close TxAttemptBuilder")) + } return nil }) @@ -258,17 +260,17 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Name() str } func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HealthReport() map[string]error { - report := map[string]error{b.Name(): b.StartStopOnce.Healthy()} + report := map[string]error{b.Name(): b.Healthy()} // only query if txm started properly b.IfStarted(func() { - maps.Copy(report, b.broadcaster.HealthReport()) - maps.Copy(report, b.confirmer.HealthReport()) - maps.Copy(report, b.txAttemptBuilder.HealthReport()) + services.CopyHealth(report, b.broadcaster.HealthReport()) + services.CopyHealth(report, b.confirmer.HealthReport()) + services.CopyHealth(report, b.txAttemptBuilder.HealthReport()) }) if b.txConfig.ForwardersEnabled() { - maps.Copy(report, b.fwdMgr.HealthReport()) + services.CopyHealth(report, b.fwdMgr.HealthReport()) } return report } @@ -435,14 +437,14 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Trigger(ad } // CreateTransaction inserts a new transaction -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], qs ...pg.QOpt) (tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { // Check for existing Tx with IdempotencyKey. If found, return the Tx and do nothing // Skipping CreateTransaction to avoid double send if txRequest.IdempotencyKey != nil { var existingTx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - existingTx, err = b.txStore.FindTxWithIdempotencyKey(*txRequest.IdempotencyKey, b.chainID) + existingTx, err = b.txStore.FindTxWithIdempotencyKey(ctx, *txRequest.IdempotencyKey, b.chainID) if err != nil && !errors.Is(err, sql.ErrNoRows) { - return tx, errors.Wrap(err, "Failed to search for transaction with IdempotencyKey") + return tx, pkgerrors.Wrap(err, "Failed to search for transaction with IdempotencyKey") } if existingTx != nil { b.logger.Infow("Found a Tx with IdempotencyKey. Returning existing Tx without creating a new one.", "IdempotencyKey", *txRequest.IdempotencyKey) @@ -472,19 +474,19 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTran } } - err = b.txStore.CheckTxQueueCapacity(txRequest.FromAddress, b.txConfig.MaxQueued(), b.chainID, qs...) + err = b.txStore.CheckTxQueueCapacity(ctx, txRequest.FromAddress, b.txConfig.MaxQueued(), b.chainID) if err != nil { - return tx, errors.Wrap(err, "Txm#CreateTransaction") + return tx, pkgerrors.Wrap(err, "Txm#CreateTransaction") } - tx, err = b.txStore.CreateTransaction(txRequest, b.chainID, qs...) + tx, err = b.txStore.CreateTransaction(ctx, txRequest, b.chainID) return } // Calls forwarderMgr to get a proper forwarder for a given EOA. func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForwarderForEOA(eoa ADDR) (forwarder ADDR, err error) { if !b.txConfig.ForwardersEnabled() { - return forwarder, errors.Errorf("Forwarding is not enabled, to enable set Transactions.ForwardersEnabled =true") + return forwarder, pkgerrors.Errorf("Forwarding is not enabled, to enable set Transactions.ForwardersEnabled =true") } forwarder, err = b.fwdMgr.ForwarderFor(eoa) return @@ -492,11 +494,11 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetForward func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) checkEnabled(addr ADDR) error { err := b.keyStore.CheckEnabled(addr, b.chainID) - return errors.Wrapf(err, "cannot send transaction from %s on chain ID %s", addr, b.chainID.String()) + return pkgerrors.Wrapf(err, "cannot send transaction from %s on chain ID %s", addr, b.chainID.String()) } // SendNativeToken creates a transaction that transfers the given value of native tokens -func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNativeToken(chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { if utils.IsZero(to) { return etx, errors.New("cannot send native token to zero address") } @@ -508,8 +510,8 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SendNative FeeLimit: gasLimit, Strategy: NewSendEveryStrategy(), } - etx, err = b.txStore.CreateTransaction(txRequest, chainID) - return etx, errors.Wrap(err, "SendNativeToken failed to insert tx") + etx, err = b.txStore.CreateTransaction(ctx, txRequest, chainID) + return etx, pkgerrors.Wrap(err, "SendNativeToken failed to insert tx") } type NullTxManager[ @@ -540,18 +542,18 @@ func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Clo func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Trigger(ADDR) { panic(n.ErrMsg) } -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(txmgrtypes.TxRequest[ADDR, TX_HASH], ...pg.QOpt) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return etx, errors.New(n.ErrMsg) } func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(addr ADDR) (fwdr ADDR, err error) { return fwdr, err } -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(f func(), addr ADDR, abandon bool) error { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { return nil } // SendNativeToken does nothing, null functionality -func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { +func (n *NullTxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from, to ADDR, value big.Int, gasLimit uint32) (etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) { return etx, errors.New(n.ErrMsg) } diff --git a/common/txmgr/types/keystore.go b/common/txmgr/types/keystore.go index 4793e6579ad..9c5b8cfce37 100644 --- a/common/txmgr/types/keystore.go +++ b/common/txmgr/types/keystore.go @@ -2,7 +2,6 @@ package types import ( "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // KeyStore encompasses the subset of keystore used by txmgr @@ -17,8 +16,6 @@ type KeyStore[ SEQ types.Sequence, ] interface { CheckEnabled(address ADDR, chainID CHAIN_ID) error - NextSequence(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (SEQ, error) EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) - IncrementNextSequence(address ADDR, chainID CHAIN_ID, currentSequence SEQ, qopts ...pg.QOpt) error SubscribeToKeyChanges() (ch chan struct{}, unsub func()) } diff --git a/common/txmgr/types/mocks/forwarder_manager.go b/common/txmgr/types/mocks/forwarder_manager.go index b508cb5a5e5..abf176550b2 100644 --- a/common/txmgr/types/mocks/forwarder_manager.go +++ b/common/txmgr/types/mocks/forwarder_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -137,13 +137,12 @@ func (_m *ForwarderManager[ADDR]) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewForwarderManager interface { +// NewForwarderManager creates a new instance of ForwarderManager. 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 NewForwarderManager[ADDR types.Hashable](t interface { mock.TestingT Cleanup(func()) -} - -// NewForwarderManager creates a new instance of ForwarderManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewForwarderManager[ADDR types.Hashable](t mockConstructorTestingTNewForwarderManager) *ForwarderManager[ADDR] { +}) *ForwarderManager[ADDR] { mock := &ForwarderManager[ADDR]{} mock.Mock.Test(t) diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index 90d8040f3e4..ad5178c09d1 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -1,9 +1,8 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" mock "github.com/stretchr/testify/mock" types "github.com/smartcontractkit/chainlink/v2/common/types" @@ -54,58 +53,6 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ return r0, r1 } -// IncrementNextSequence provides a mock function with given fields: address, chainID, currentSequence, qopts -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) IncrementNextSequence(address ADDR, chainID CHAIN_ID, currentSequence SEQ, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, currentSequence) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, SEQ, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, currentSequence, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NextSequence provides a mock function with given fields: address, chainID, qopts -func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) NextSequence(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (SEQ, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 SEQ - var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) (SEQ, error)); ok { - return rf(address, chainID, qopts...) - } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) SEQ); ok { - r0 = rf(address, chainID, qopts...) - } else { - r0 = ret.Get(0).(SEQ) - } - - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // SubscribeToKeyChanges provides a mock function with given fields: func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() @@ -134,13 +81,12 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, return r0, r1 } -type mockConstructorTestingTNewKeyStore interface { +// NewKeyStore creates a new instance of KeyStore. 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 NewKeyStore[ADDR types.Hashable, CHAIN_ID types.ID, SEQ types.Sequence](t interface { mock.TestingT Cleanup(func()) -} - -// NewKeyStore creates a new instance of KeyStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewKeyStore[ADDR types.Hashable, CHAIN_ID types.ID, SEQ types.Sequence](t mockConstructorTestingTNewKeyStore) *KeyStore[ADDR, CHAIN_ID, SEQ] { +}) *KeyStore[ADDR, CHAIN_ID, SEQ] { mock := &KeyStore[ADDR, CHAIN_ID, SEQ]{} mock.Mock.Test(t) diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go index ae212f23d81..a733b223701 100644 --- a/common/txmgr/types/mocks/reaper_chain_config.go +++ b/common/txmgr/types/mocks/reaper_chain_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -23,13 +23,12 @@ func (_m *ReaperConfig) FinalityDepth() uint32 { return r0 } -type mockConstructorTestingTNewReaperConfig interface { +// NewReaperConfig creates a new instance of ReaperConfig. 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 NewReaperConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewReaperConfig creates a new instance of ReaperConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewReaperConfig(t mockConstructorTestingTNewReaperConfig) *ReaperConfig { +}) *ReaperConfig { mock := &ReaperConfig{} mock.Mock.Test(t) diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index cda71cfae09..f49b0025ae7 100644 --- a/common/txmgr/types/mocks/tx_attempt_builder.go +++ b/common/txmgr/types/mocks/tx_attempt_builder.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -301,13 +301,12 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) return r0 } -type mockConstructorTestingTNewTxAttemptBuilder interface { +// NewTxAttemptBuilder creates a new instance of TxAttemptBuilder. 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 NewTxAttemptBuilder[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence, FEE feetypes.Fee](t interface { mock.TestingT Cleanup(func()) -} - -// NewTxAttemptBuilder creates a new instance of TxAttemptBuilder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTxAttemptBuilder[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashable, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, SEQ types.Sequence, FEE feetypes.Fee](t mockConstructorTestingTNewTxAttemptBuilder) *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { +}) *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { mock := &TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{} mock.Mock.Test(t) diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index 9c812788bf6..02388e40f40 100644 --- a/common/txmgr/types/mocks/tx_store.go +++ b/common/txmgr/types/mocks/tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -8,8 +8,6 @@ import ( feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - time "time" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -24,13 +22,13 @@ type TxStore[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLO mock.Mock } -// Abandon provides a mock function with given fields: id, addr -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(id CHAIN_ID, addr ADDR) error { - ret := _m.Called(id, addr) +// Abandon provides a mock function with given fields: ctx, id, addr +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(ctx context.Context, id CHAIN_ID, addr ADDR) error { + ret := _m.Called(ctx, id, addr) var r0 error - if rf, ok := ret.Get(0).(func(CHAIN_ID, ADDR) error); ok { - r0 = rf(id, addr) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR) error); ok { + r0 = rf(ctx, id, addr) } else { r0 = ret.Error(0) } @@ -38,20 +36,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(id return r0 } -// CheckTxQueueCapacity provides a mock function with given fields: fromAddress, maxQueuedTransactions, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckTxQueueCapacity(fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, maxQueuedTransactions, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CheckTxQueueCapacity provides a mock function with given fields: ctx, fromAddress, maxQueuedTransactions, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckTxQueueCapacity(ctx context.Context, fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID) error { + ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) var r0 error - if rf, ok := ret.Get(0).(func(ADDR, uint64, CHAIN_ID, ...pg.QOpt) error); ok { - r0 = rf(fromAddress, maxQueuedTransactions, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, uint64, CHAIN_ID) error); ok { + r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) } else { r0 = ret.Error(0) } @@ -64,30 +55,23 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() { _m.Called() } -// CountUnconfirmedTransactions provides a mock function with given fields: fromAddress, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconfirmedTransactions(fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (uint32, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CountUnconfirmedTransactions provides a mock function with given fields: ctx, fromAddress, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { + ret := _m.Called(ctx, fromAddress, chainID) var r0 uint32 var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) (uint32, error)); ok { - return rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { + return rf(ctx, fromAddress, chainID) } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) uint32); ok { - r0 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) uint32); ok { + r0 = rf(ctx, fromAddress, chainID) } else { r0 = ret.Get(0).(uint32) } - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, fromAddress, chainID) } else { r1 = ret.Error(1) } @@ -95,30 +79,23 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconf return r0, r1 } -// CountUnstartedTransactions provides a mock function with given fields: fromAddress, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstartedTransactions(fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (uint32, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CountUnstartedTransactions provides a mock function with given fields: ctx, fromAddress, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { + ret := _m.Called(ctx, fromAddress, chainID) var r0 uint32 var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) (uint32, error)); ok { - return rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { + return rf(ctx, fromAddress, chainID) } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) uint32); ok { - r0 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) uint32); ok { + r0 = rf(ctx, fromAddress, chainID) } else { r0 = ret.Get(0).(uint32) } - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, fromAddress, chainID) } else { r1 = ret.Error(1) } @@ -126,30 +103,23 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstar return r0, r1 } -// CreateTransaction provides a mock function with given fields: txRequest, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], chainID CHAIN_ID, qopts ...pg.QOpt) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, txRequest, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CreateTransaction provides a mock function with given fields: ctx, txRequest, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, txRequest, chainID) var r0 txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID, ...pg.QOpt) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, txRequest, chainID) } - if rf, ok := ret.Get(0).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID, ...pg.QOpt) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID) txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, txRequest, chainID) } else { r0 = ret.Get(0).(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } - if rf, ok := ret.Get(1).(func(txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID) error); ok { + r1 = rf(ctx, txRequest, chainID) } else { r1 = ret.Error(1) } @@ -171,20 +141,37 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInPro return r0 } -// FindNextUnstartedTransactionFromAddress provides a mock function with given fields: etx, fromAddress, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUnstartedTransactionFromAddress(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] +// FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) { + ret := _m.Called(ctx, fromAddress, chainId) + + var r0 SEQ + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (SEQ, error)); ok { + return rf(ctx, fromAddress, chainId) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) SEQ); ok { + r0 = rf(ctx, fromAddress, chainId) + } else { + r0 = ret.Get(0).(SEQ) + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, fromAddress, chainId) + } else { + r1 = ret.Error(1) } - var _ca []interface{} - _ca = append(_ca, etx, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) + + return r0, r1 +} + +// FindNextUnstartedTransactionFromAddress provides a mock function with given fields: ctx, etx, fromAddress, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error { + ret := _m.Called(ctx, etx, fromAddress, chainID) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r0 = rf(etx, fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ADDR, CHAIN_ID) error); ok { + r0 = rf(ctx, etx, fromAddress, chainID) } else { r0 = ret.Error(0) } @@ -218,25 +205,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindReceipt return r0, r1 } -// FindTransactionsConfirmedInBlockRange provides a mock function with given fields: highBlockNumber, lowBlockNumber, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransactionsConfirmedInBlockRange(highBlockNumber int64, lowBlockNumber int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(highBlockNumber, lowBlockNumber, chainID) +// FindTransactionsConfirmedInBlockRange provides a mock function with given fields: ctx, highBlockNumber, lowBlockNumber, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, highBlockNumber, lowBlockNumber, chainID) } - if rf, ok := ret.Get(0).(func(int64, int64, CHAIN_ID) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, highBlockNumber, lowBlockNumber, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(int64, int64, CHAIN_ID) error); ok { - r1 = rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(1).(func(context.Context, int64, int64, CHAIN_ID) error); ok { + r1 = rf(ctx, highBlockNumber, lowBlockNumber, chainID) } else { r1 = ret.Error(1) } @@ -244,25 +231,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransac return r0, r1 } -// FindTxAttemptsConfirmedMissingReceipt provides a mock function with given fields: chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsConfirmedMissingReceipt(chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(chainID) +// FindTxAttemptsConfirmedMissingReceipt provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, chainID) var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(CHAIN_ID) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -270,25 +257,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem return r0, r1 } -// FindTxAttemptsRequiringReceiptFetch provides a mock function with given fields: chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringReceiptFetch(chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(chainID) +// FindTxAttemptsRequiringReceiptFetch provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, chainID) var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(CHAIN_ID) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -296,25 +283,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem return r0, r1 } -// FindTxAttemptsRequiringResend provides a mock function with given fields: olderThan, maxInFlightTransactions, chainID, address -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringResend(olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(olderThan, maxInFlightTransactions, chainID, address) +// FindTxAttemptsRequiringResend provides a mock function with given fields: ctx, olderThan, maxInFlightTransactions, chainID, address +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) var r0 []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(time.Time, uint32, CHAIN_ID, ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, CHAIN_ID, ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } - if rf, ok := ret.Get(0).(func(time.Time, uint32, CHAIN_ID, ADDR) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, CHAIN_ID, ADDR) []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(time.Time, uint32, CHAIN_ID, ADDR) error); ok { - r1 = rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(1).(func(context.Context, time.Time, uint32, CHAIN_ID, ADDR) error); ok { + r1 = rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } else { r1 = ret.Error(1) } @@ -322,25 +309,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem return r0, r1 } -// FindTxWithIdempotencyKey provides a mock function with given fields: idempotencyKey, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithIdempotencyKey(idempotencyKey string, chainID CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(idempotencyKey, chainID) +// FindTxWithIdempotencyKey provides a mock function with given fields: ctx, idempotencyKey, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, idempotencyKey, chainID) var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(string, CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(idempotencyKey, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, idempotencyKey, chainID) } - if rf, ok := ret.Get(0).(func(string, CHAIN_ID) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(idempotencyKey, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, CHAIN_ID) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, idempotencyKey, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(string, CHAIN_ID) error); ok { - r1 = rf(idempotencyKey, chainID) + if rf, ok := ret.Get(1).(func(context.Context, string, CHAIN_ID) error); ok { + r1 = rf(ctx, idempotencyKey, chainID) } else { r1 = ret.Error(1) } @@ -348,25 +335,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithI return r0, r1 } -// FindTxWithSequence provides a mock function with given fields: fromAddress, seq -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithSequence(fromAddress ADDR, seq SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - ret := _m.Called(fromAddress, seq) +// FindTxWithSequence provides a mock function with given fields: ctx, fromAddress, seq +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, fromAddress, seq) var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(ADDR, SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(fromAddress, seq) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, fromAddress, seq) } - if rf, ok := ret.Get(0).(func(ADDR, SEQ) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(fromAddress, seq) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, SEQ) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, fromAddress, seq) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(ADDR, SEQ) error); ok { - r1 = rf(fromAddress, seq) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, SEQ) error); ok { + r1 = rf(ctx, fromAddress, seq) } else { r1 = ret.Error(1) } @@ -400,32 +387,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ return r0, r1 } -// FindTxsRequiringResubmissionDueToInsufficientFunds provides a mock function with given fields: address, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringResubmissionDueToInsufficientFunds(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// FindTxsRequiringResubmissionDueToInsufficientFunds provides a mock function with given fields: ctx, address, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, address, chainID) var r0 []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, address, chainID) } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) []*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, address, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, address, chainID) } else { r1 = ret.Error(1) } @@ -459,32 +439,25 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgre return r0, r1 } -// GetTxInProgress provides a mock function with given fields: fromAddress, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProgress(fromAddress ADDR, qopts ...pg.QOpt) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// GetTxInProgress provides a mock function with given fields: ctx, fromAddress +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProgress(ctx context.Context, fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { + ret := _m.Called(ctx, fromAddress) var r0 *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error - if rf, ok := ret.Get(0).(func(ADDR, ...pg.QOpt) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { - return rf(fromAddress, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { + return rf(ctx, fromAddress) } - if rf, ok := ret.Get(0).(func(ADDR, ...pg.QOpt) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { - r0 = rf(fromAddress, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR) *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]); ok { + r0 = rf(ctx, fromAddress) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) } } - if rf, ok := ret.Get(1).(func(ADDR, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, ADDR) error); ok { + r1 = rf(ctx, fromAddress) } else { r1 = ret.Error(1) } @@ -492,30 +465,23 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProg return r0, r1 } -// HasInProgressTransaction provides a mock function with given fields: account, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgressTransaction(account ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (bool, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, account, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// HasInProgressTransaction provides a mock function with given fields: ctx, account, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (bool, error) { + ret := _m.Called(ctx, account, chainID) var r0 bool var r1 error - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) (bool, error)); ok { - return rf(account, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (bool, error)); ok { + return rf(ctx, account, chainID) } - if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID, ...pg.QOpt) bool); ok { - r0 = rf(account, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) bool); ok { + r0 = rf(ctx, account, chainID) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r1 = rf(account, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, ADDR, CHAIN_ID) error); ok { + r1 = rf(ctx, account, chainID) } else { r1 = ret.Error(1) } @@ -523,20 +489,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgre return r0, r1 } -// LoadTxAttempts provides a mock function with given fields: etx, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// LoadTxAttempts provides a mock function with given fields: ctx, etx +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, etx) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ...pg.QOpt) error); ok { - r0 = rf(etx, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, etx) } else { r0 = ret.Error(0) } @@ -544,13 +503,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttem return r0 } -// MarkAllConfirmedMissingReceipt provides a mock function with given fields: chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConfirmedMissingReceipt(chainID CHAIN_ID) error { - ret := _m.Called(chainID) +// MarkAllConfirmedMissingReceipt provides a mock function with given fields: ctx, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) error { + ret := _m.Called(ctx, chainID) var r0 error - if rf, ok := ret.Get(0).(func(CHAIN_ID) error); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) error); ok { + r0 = rf(ctx, chainID) } else { r0 = ret.Error(0) } @@ -558,20 +517,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConf return r0 } -// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: blockNum, finalityDepth, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(blockNum int64, finalityDepth uint32, chainID CHAIN_ID, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, blockNum, finalityDepth, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, finalityDepth, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error { + ret := _m.Called(ctx, blockNum, finalityDepth, chainID) var r0 error - if rf, ok := ret.Get(0).(func(int64, uint32, CHAIN_ID, ...pg.QOpt) error); ok { - r0 = rf(blockNum, finalityDepth, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, CHAIN_ID) error); ok { + r0 = rf(ctx, blockNum, finalityDepth, chainID) } else { r0 = ret.Error(0) } @@ -579,20 +531,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxes return r0 } -// PreloadTxes provides a mock function with given fields: attempts, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes(attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, attempts) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// PreloadTxes provides a mock function with given fields: ctx, attempts +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes(ctx context.Context, attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, attempts) var r0 error - if rf, ok := ret.Get(0).(func([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ...pg.QOpt) error); ok { - r0 = rf(attempts, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, attempts) } else { r0 = ret.Error(0) } @@ -600,30 +545,23 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes return r0 } -// PruneUnstartedTxQueue provides a mock function with given fields: queueSize, subject, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qopts ...pg.QOpt) (int64, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, queueSize, subject) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// PruneUnstartedTxQueue provides a mock function with given fields: ctx, queueSize, subject +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { + ret := _m.Called(ctx, queueSize, subject) var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(uint32, uuid.UUID, ...pg.QOpt) (int64, error)); ok { - return rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { + return rf(ctx, queueSize, subject) } - if rf, ok := ret.Get(0).(func(uint32, uuid.UUID, ...pg.QOpt) int64); ok { - r0 = rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) int64); ok { + r0 = rf(ctx, queueSize, subject) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(uint32, uuid.UUID, ...pg.QOpt) error); ok { - r1 = rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, uint32, uuid.UUID) error); ok { + r1 = rf(ctx, queueSize, subject) } else { r1 = ret.Error(1) } @@ -631,13 +569,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstar return r0, r1 } -// ReapTxHistory provides a mock function with given fields: minBlockNumberToKeep, timeThreshold, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error { - ret := _m.Called(minBlockNumberToKeep, timeThreshold, chainID) +// ReapTxHistory provides a mock function with given fields: ctx, minBlockNumberToKeep, timeThreshold, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error { + ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) var r0 error - if rf, ok := ret.Get(0).(func(int64, time.Time, CHAIN_ID) error); ok { - r0 = rf(minBlockNumberToKeep, timeThreshold, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, CHAIN_ID) error); ok { + r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) } else { r0 = ret.Error(0) } @@ -659,13 +597,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveConfirm return r0 } -// SaveFetchedReceipts provides a mock function with given fields: receipts, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetchedReceipts(receipts []R, chainID CHAIN_ID) error { - ret := _m.Called(receipts, chainID) +// SaveFetchedReceipts provides a mock function with given fields: ctx, receipts, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetchedReceipts(ctx context.Context, receipts []R, chainID CHAIN_ID) error { + ret := _m.Called(ctx, receipts, chainID) var r0 error - if rf, ok := ret.Get(0).(func([]R, CHAIN_ID) error); ok { - r0 = rf(receipts, chainID) + if rf, ok := ret.Get(0).(func(context.Context, []R, CHAIN_ID) error); ok { + r0 = rf(ctx, receipts, chainID) } else { r0 = ret.Error(0) } @@ -673,27 +611,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetched return r0 } -// SaveInProgressAttempt provides a mock function with given fields: attempt -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgressAttempt(attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { - ret := _m.Called(attempt) - - var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { - r0 = rf(attempt) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SaveInsufficientFundsAttempt provides a mock function with given fields: timeout, attempt, broadcastAt -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsufficientFundsAttempt(timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { - ret := _m.Called(timeout, attempt, broadcastAt) +// SaveInProgressAttempt provides a mock function with given fields: ctx, attempt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgressAttempt(ctx context.Context, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, attempt) var r0 error - if rf, ok := ret.Get(0).(func(time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { - r0 = rf(timeout, attempt, broadcastAt) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, attempt) } else { r0 = ret.Error(0) } @@ -701,20 +625,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsuffi return r0 } -// SaveReplacementInProgressAttempt provides a mock function with given fields: oldAttempt, replacementAttempt, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplacementInProgressAttempt(oldAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, oldAttempt, replacementAttempt) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// SaveInsufficientFundsAttempt provides a mock function with given fields: ctx, timeout, attempt, broadcastAt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { + ret := _m.Called(ctx, timeout, attempt, broadcastAt) var r0 error - if rf, ok := ret.Get(0).(func(txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ...pg.QOpt) error); ok { - r0 = rf(oldAttempt, replacementAttempt, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { + r0 = rf(ctx, timeout, attempt, broadcastAt) } else { r0 = ret.Error(0) } @@ -722,13 +639,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplace return r0 } -// SaveSentAttempt provides a mock function with given fields: timeout, attempt, broadcastAt -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAttempt(timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { - ret := _m.Called(timeout, attempt, broadcastAt) +// SaveReplacementInProgressAttempt provides a mock function with given fields: ctx, oldAttempt, replacementAttempt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, oldAttempt, replacementAttempt) var r0 error - if rf, ok := ret.Get(0).(func(time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { - r0 = rf(timeout, attempt, broadcastAt) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, oldAttempt, replacementAttempt) } else { r0 = ret.Error(0) } @@ -736,13 +653,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAtt return r0 } -// SetBroadcastBeforeBlockNum provides a mock function with given fields: blockNum, chainID -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcastBeforeBlockNum(blockNum int64, chainID CHAIN_ID) error { - ret := _m.Called(blockNum, chainID) +// SaveSentAttempt provides a mock function with given fields: ctx, timeout, attempt, broadcastAt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { + ret := _m.Called(ctx, timeout, attempt, broadcastAt) var r0 error - if rf, ok := ret.Get(0).(func(int64, CHAIN_ID) error); ok { - r0 = rf(blockNum, chainID) + if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { + r0 = rf(ctx, timeout, attempt, broadcastAt) } else { r0 = ret.Error(0) } @@ -750,13 +667,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcas return r0 } -// UpdateBroadcastAts provides a mock function with given fields: now, etxIDs -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { - ret := _m.Called(now, etxIDs) +// SetBroadcastBeforeBlockNum provides a mock function with given fields: ctx, blockNum, chainID +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error { + ret := _m.Called(ctx, blockNum, chainID) var r0 error - if rf, ok := ret.Get(0).(func(time.Time, []int64) error); ok { - r0 = rf(now, etxIDs) + if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) error); ok { + r0 = rf(ctx, blockNum, chainID) } else { r0 = ret.Error(0) } @@ -764,20 +681,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroad return r0 } -// UpdateKeyNextSequence provides a mock function with given fields: newNextSequence, currentNextSequence, address, chainID, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateKeyNextSequence(newNextSequence SEQ, currentNextSequence SEQ, address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, newNextSequence, currentNextSequence, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateBroadcastAts provides a mock function with given fields: ctx, now, etxIDs +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { + ret := _m.Called(ctx, now, etxIDs) var r0 error - if rf, ok := ret.Get(0).(func(SEQ, SEQ, ADDR, CHAIN_ID, ...pg.QOpt) error); ok { - r0 = rf(newNextSequence, currentNextSequence, address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { + r0 = rf(ctx, now, etxIDs) } else { r0 = ret.Error(0) } @@ -785,20 +695,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateKeyNe return r0 } -// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState, incrNextSequenceCallback func(pg.Queryer) error, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt, NewAttemptState, incrNextSequenceCallback) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: ctx, etx, attempt, NewAttemptState +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState) error { + ret := _m.Called(ctx, etx, attempt, NewAttemptState) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState, func(pg.Queryer) error, ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState) error); ok { + r0 = rf(ctx, etx, attempt, NewAttemptState) } else { r0 = ret.Error(0) } @@ -806,20 +709,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAtt return r0 } -// UpdateTxFatalError provides a mock function with given fields: etx, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFatalError(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxFatalError provides a mock function with given fields: ctx, etx +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFatalError(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, etx) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ...pg.QOpt) error); ok { - r0 = rf(etx, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, etx) } else { r0 = ret.Error(0) } @@ -827,13 +723,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFat return r0 } -// UpdateTxForRebroadcast provides a mock function with given fields: etx, etxAttempt -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxForRebroadcast(etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { - ret := _m.Called(etx, etxAttempt) +// UpdateTxForRebroadcast provides a mock function with given fields: ctx, etx, etxAttempt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxForRebroadcast(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, etx, etxAttempt) var r0 error - if rf, ok := ret.Get(0).(func(txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { - r0 = rf(etx, etxAttempt) + if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, etx, etxAttempt) } else { r0 = ret.Error(0) } @@ -841,20 +737,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFor return r0 } -// UpdateTxUnstartedToInProgress provides a mock function with given fields: etx, attempt, qopts -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUnstartedToInProgress(etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxUnstartedToInProgress provides a mock function with given fields: ctx, etx, attempt +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUnstartedToInProgress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { + ret := _m.Called(ctx, etx, attempt) var r0 error - if rf, ok := ret.Get(0).(func(*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { + r0 = rf(ctx, etx, attempt) } else { r0 = ret.Error(0) } @@ -862,13 +751,13 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUns return r0 } -// UpdateTxsUnconfirmed provides a mock function with given fields: ids -func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxsUnconfirmed(ids []int64) error { - ret := _m.Called(ids) +// UpdateTxsUnconfirmed provides a mock function with given fields: ctx, ids +func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { + ret := _m.Called(ctx, ids) var r0 error - if rf, ok := ret.Get(0).(func([]int64) error); ok { - r0 = rf(ids) + if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { + r0 = rf(ctx, ids) } else { r0 = ret.Error(0) } @@ -876,13 +765,12 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxsUn return r0 } -type mockConstructorTestingTNewTxStore interface { +// NewTxStore creates a new instance of TxStore. 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 NewTxStore[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], SEQ types.Sequence, FEE feetypes.Fee](t interface { mock.TestingT Cleanup(func()) -} - -// NewTxStore creates a new instance of TxStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTxStore[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], SEQ types.Sequence, FEE feetypes.Fee](t mockConstructorTestingTNewTxStore) *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { +}) *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { mock := &TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{} mock.Mock.Test(t) diff --git a/common/txmgr/types/mocks/tx_strategy.go b/common/txmgr/types/mocks/tx_strategy.go index 74d3182947e..f4ec9bef49a 100644 --- a/common/txmgr/types/mocks/tx_strategy.go +++ b/common/txmgr/types/mocks/tx_strategy.go @@ -1,10 +1,11 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( + context "context" + types "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" mock "github.com/stretchr/testify/mock" uuid "github.com/google/uuid" @@ -15,23 +16,23 @@ type TxStrategy struct { mock.Mock } -// PruneQueue provides a mock function with given fields: pruneService, qopt -func (_m *TxStrategy) PruneQueue(pruneService types.UnstartedTxQueuePruner, qopt pg.QOpt) (int64, error) { - ret := _m.Called(pruneService, qopt) +// PruneQueue provides a mock function with given fields: ctx, pruneService +func (_m *TxStrategy) PruneQueue(ctx context.Context, pruneService types.UnstartedTxQueuePruner) (int64, error) { + ret := _m.Called(ctx, pruneService) var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(types.UnstartedTxQueuePruner, pg.QOpt) (int64, error)); ok { - return rf(pruneService, qopt) + if rf, ok := ret.Get(0).(func(context.Context, types.UnstartedTxQueuePruner) (int64, error)); ok { + return rf(ctx, pruneService) } - if rf, ok := ret.Get(0).(func(types.UnstartedTxQueuePruner, pg.QOpt) int64); ok { - r0 = rf(pruneService, qopt) + if rf, ok := ret.Get(0).(func(context.Context, types.UnstartedTxQueuePruner) int64); ok { + r0 = rf(ctx, pruneService) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(types.UnstartedTxQueuePruner, pg.QOpt) error); ok { - r1 = rf(pruneService, qopt) + if rf, ok := ret.Get(1).(func(context.Context, types.UnstartedTxQueuePruner) error); ok { + r1 = rf(ctx, pruneService) } else { r1 = ret.Error(1) } @@ -53,13 +54,12 @@ func (_m *TxStrategy) Subject() uuid.NullUUID { return r0 } -type mockConstructorTestingTNewTxStrategy interface { +// NewTxStrategy creates a new instance of TxStrategy. 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 NewTxStrategy(t interface { mock.TestingT Cleanup(func()) -} - -// NewTxStrategy creates a new instance of TxStrategy. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTxStrategy(t mockConstructorTestingTNewTxStrategy) *TxStrategy { +}) *TxStrategy { mock := &TxStrategy{} mock.Mock.Test(t) diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index a0faa81c3aa..d95f07afabc 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -1,22 +1,22 @@ package types import ( + "context" "encoding/json" "fmt" "math/big" + "slices" "strings" "time" "github.com/google/uuid" "github.com/pkg/errors" - "golang.org/x/exp/slices" "gopkg.in/guregu/null.v4" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/logger" clnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pg/datatypes" ) @@ -29,7 +29,7 @@ type TxStrategy interface { // PruneQueue is called after tx insertion // It accepts the service responsible for deleting // unstarted txs and deletion options - PruneQueue(pruneService UnstartedTxQueuePruner, qopt pg.QOpt) (n int64, err error) + PruneQueue(ctx context.Context, pruneService UnstartedTxQueuePruner) (n int64, err error) } type TxAttemptState int8 diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go index 8c56b8a6ed6..059a87d7ab2 100644 --- a/common/txmgr/types/tx_store.go +++ b/common/txmgr/types/tx_store.go @@ -34,16 +34,15 @@ type TxStore[ UnstartedTxQueuePruner TxHistoryReaper[CHAIN_ID] TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] - SequenceStore[ADDR, CHAIN_ID, SEQ] // methods for saving & retreiving receipts FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID CHAIN_ID) (receiptsPlus []ReceiptPlus[R], err error) - SaveFetchedReceipts(receipts []R, chainID CHAIN_ID) (err error) + SaveFetchedReceipts(ctx context.Context, receipts []R, chainID CHAIN_ID) (err error) // additional methods for tx store management - CheckTxQueueCapacity(fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID, qopts ...pg.QOpt) (err error) + CheckTxQueueCapacity(ctx context.Context, fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID) (err error) Close() - Abandon(id CHAIN_ID, addr ADDR) error + Abandon(ctx context.Context, id CHAIN_ID, addr ADDR) error } // TransactionStore contains the persistence layer methods needed to manage Txs and TxAttempts @@ -55,56 +54,49 @@ type TransactionStore[ SEQ types.Sequence, FEE feetypes.Fee, ] interface { - CountUnconfirmedTransactions(fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (count uint32, err error) - CountUnstartedTransactions(fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (count uint32, err error) - CreateTransaction(txRequest TxRequest[ADDR, TX_HASH], chainID CHAIN_ID, qopts ...pg.QOpt) (tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (count uint32, err error) + CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (count uint32, err error) + CreateTransaction(ctx context.Context, txRequest TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) DeleteInProgressAttempt(ctx context.Context, attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) FindTxsRequiringGasBump(ctx context.Context, address ADDR, blockNum, gasBumpThreshold, depth int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - FindTxsRequiringResubmissionDueToInsufficientFunds(address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - FindTxAttemptsConfirmedMissingReceipt(chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - FindTxAttemptsRequiringReceiptFetch(chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - FindTxAttemptsRequiringResend(olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address ADDR, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) // Search for Tx using the idempotencyKey and chainID - FindTxWithIdempotencyKey(idempotencyKey string, chainID CHAIN_ID) (tx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID CHAIN_ID) (tx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) // Search for Tx using the fromAddress and sequence - FindTxWithSequence(fromAddress ADDR, seq SEQ) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - FindNextUnstartedTransactionFromAddress(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error - FindTransactionsConfirmedInBlockRange(highBlockNumber, lowBlockNumber int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - GetTxInProgress(fromAddress ADDR, qopts ...pg.QOpt) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error + FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber, lowBlockNumber int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) + GetTxInProgress(ctx context.Context, fromAddress ADDR) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) GetInProgressTxAttempts(ctx context.Context, address ADDR, chainID CHAIN_ID) (attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error) - HasInProgressTransaction(account ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) (exists bool, err error) - LoadTxAttempts(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error - MarkAllConfirmedMissingReceipt(chainID CHAIN_ID) (err error) - MarkOldTxesMissingReceiptAsErrored(blockNum int64, finalityDepth uint32, chainID CHAIN_ID, qopts ...pg.QOpt) error - PreloadTxes(attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error + HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (exists bool, err error) + LoadTxAttempts(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) (err error) + MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error + PreloadTxes(ctx context.Context, attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error - SaveInProgressAttempt(attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error - SaveInsufficientFundsAttempt(timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error - SaveReplacementInProgressAttempt(oldAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error - SaveSentAttempt(timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error - SetBroadcastBeforeBlockNum(blockNum int64, chainID CHAIN_ID) error - UpdateBroadcastAts(now time.Time, etxIDs []int64) error - UpdateTxAttemptInProgressToBroadcast(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState TxAttemptState, incrNextSequenceCallback QueryerFunc, qopts ...pg.QOpt) error - UpdateTxsUnconfirmed(ids []int64) error - UpdateTxUnstartedToInProgress(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error - UpdateTxFatalError(etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], qopts ...pg.QOpt) error - UpdateTxForRebroadcast(etx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + SaveInProgressAttempt(ctx context.Context, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error + SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error + SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error + UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error + UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState TxAttemptState) error + UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error + UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + UpdateTxFatalError(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + UpdateTxForRebroadcast(ctx context.Context, etx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error } type TxHistoryReaper[CHAIN_ID types.ID] interface { - ReapTxHistory(minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error + ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error } type UnstartedTxQueuePruner interface { - PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qopts ...pg.QOpt) (n int64, err error) -} - -type SequenceStore[ - ADDR types.Hashable, - CHAIN_ID types.ID, - SEQ types.Sequence, -] interface { - UpdateKeyNextSequence(newNextSequence, currentNextSequence SEQ, address ADDR, chainID CHAIN_ID, qopts ...pg.QOpt) error + PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (n int64, err error) } // R is the raw unparsed transaction receipt diff --git a/common/types/chain.go b/common/types/chain.go index 800f0d9fdc0..c2c2011d8de 100644 --- a/common/types/chain.go +++ b/common/types/chain.go @@ -9,6 +9,9 @@ type Sequence interface { Int64() int64 // needed for numeric sequence confirmation - to be removed with confirmation logic generalization: https://smartcontract-it.atlassian.net/browse/BCI-860 } +// Generate the next usable sequence for a transaction +type GenerateNextSequenceFunc[SEQ Sequence] func(prev SEQ) SEQ + // ID represents the base type, for any chain's ID. // It should be convertible to a string, that can uniquely identify this chain type ID fmt.Stringer diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index d3933ae1e3f..3cb303ef267 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -114,13 +114,12 @@ func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { return r0 } -type mockConstructorTestingTNewHead interface { +// NewHead creates a new instance of Head. 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 NewHead[BLOCK_HASH types.Hashable](t interface { mock.TestingT Cleanup(func()) -} - -// NewHead creates a new instance of Head. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHead[BLOCK_HASH types.Hashable](t mockConstructorTestingTNewHead) *Head[BLOCK_HASH] { +}) *Head[BLOCK_HASH] { mock := &Head[BLOCK_HASH]{} mock.Mock.Test(t) diff --git a/common/types/mocks/head_trackable.go b/common/types/mocks/head_trackable.go index 2701362918c..e63e9ca2497 100644 --- a/common/types/mocks/head_trackable.go +++ b/common/types/mocks/head_trackable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -19,13 +19,12 @@ func (_m *HeadTrackable[H, BLOCK_HASH]) OnNewLongestChain(ctx context.Context, h _m.Called(ctx, head) } -type mockConstructorTestingTNewHeadTrackable interface { +// NewHeadTrackable creates a new instance of HeadTrackable. 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 NewHeadTrackable[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t interface { mock.TestingT Cleanup(func()) -} - -// NewHeadTrackable creates a new instance of HeadTrackable. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHeadTrackable[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable](t mockConstructorTestingTNewHeadTrackable) *HeadTrackable[H, BLOCK_HASH] { +}) *HeadTrackable[H, BLOCK_HASH] { mock := &HeadTrackable[H, BLOCK_HASH]{} mock.Mock.Test(t) diff --git a/common/types/mocks/subscription.go b/common/types/mocks/subscription.go index b9cb7886d1d..5577ee4a62a 100644 --- a/common/types/mocks/subscription.go +++ b/common/types/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -30,13 +30,12 @@ func (_m *Subscription) Unsubscribe() { _m.Called() } -type mockConstructorTestingTNewSubscription interface { +// NewSubscription creates a new instance of Subscription. 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 NewSubscription(t interface { mock.TestingT Cleanup(func()) -} - -// NewSubscription creates a new instance of Subscription. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSubscription(t mockConstructorTestingTNewSubscription) *Subscription { +}) *Subscription { mock := &Subscription{} mock.Mock.Test(t) diff --git a/contracts/.solhint.json b/contracts/.solhint.json index ad3ab97846d..3b69ca6a7f2 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -1,7 +1,42 @@ { "extends": "solhint:recommended", - "plugins": ["prettier"], + "plugins": ["prettier", "chainlink-solidity"], "rules": { - "prettier/prettier": "error" + "compiler-version": ["off", "^0.8.0"], + "const-name-snakecase": "off", + "constructor-syntax": "error", + "var-name-mixedcase": "off", + "func-named-parameters": "off", + "immutable-vars-naming": "off", + "no-inline-assembly": "off", + "no-unused-import": "error", + "func-visibility": [ + "error", + { + "ignoreConstructors": true + } + ], + "not-rely-on-time": "off", + "prettier/prettier": [ + "off", + { + "endOfLine": "auto" + } + ], + "no-empty-blocks": "off", + "quotes": ["error", "double"], + "reason-string": [ + "warn", + { + "maxLength": 64 + } + ], + "chainlink-solidity/prefix-internal-functions-with-underscore": "warn", + "chainlink-solidity/prefix-private-functions-with-underscore": "warn", + "chainlink-solidity/prefix-storage-variables-with-s-underscore": "warn", + "chainlink-solidity/prefix-immutable-variables-with-i": "warn", + "chainlink-solidity/all-caps-constant-storage-variables": "warn", + "chainlink-solidity/no-hardhat-imports": "warn", + "chainlink-solidity/inherited-constructor-args-not-in-contract-definition": "warn" } } diff --git a/contracts/.solhintignore b/contracts/.solhintignore index c2658d7d1b3..1a308af94b1 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1 +1,17 @@ -node_modules/ +# 351 warnings +#./src/v0.8/automation +# 27 warnings +#./src/v0.8/functions + + +# Ignore tests, this should not be the long term plan but is OK in the short term +./src/v0.8/**/*.t.sol +./src/v0.8/mocks +./src/v0.8/tests +./src/v0.8/llo-feeds/test +./src/v0.8/vrf/testhelpers +./src/v0.8/functions/tests + +# Always ignore vendor +./src/v0.8/vendor +./node_modules/ \ No newline at end of file diff --git a/contracts/CHANGELOG.md b/contracts/CHANGELOG.md index e3ea1a31a9c..248e4f77664 100644 --- a/contracts/CHANGELOG.md +++ b/contracts/CHANGELOG.md @@ -2,7 +2,36 @@ ## Unreleased -... +- Moved `VRFCoordinatorV2Mock.sol` to src/v0.8/vrf/mocks +- Moved `VRFCoordinatorMock.sol` to src/v0.8/vrf/mocks +- Release Functions v1.0.0 contracts. Start dev folder for v1.X (#10941) +- Add minimumEstimateGasPriceWei to Functions Coordinator config (#10916) +- Remove redundant Functions Coordinator commitment & request id checks (#10975) + +### Removed + +- Removed all code related to versions prior to Solidity 0.8.0 (#10931) + +## 0.8.0 - 2023-10-04 + +### Changed + + +- Add a re-entrancy guard to VRFCoordinatorV2Mock to mimic VRFCoordinatorV2's behavior (#10585) +- Enhanced support for destination configs in Data Streams verifiers (#10472) +- Update Data Streams proxy and billing interfaces for better UX (#10603) +- Allow new reward recipients to be added to pools in Data Streams reward management (#10658) +- Reorganize Data Streams contracts (llo-feeds/) (#10727) +- Release automation 2.1 contracts (#10587) + - Note: consumers should only use IKeeperRegistryMaster when interacting with the registry contract +- Fix Functions v1 OracleWithdrawAll to correctly use transmitters (#10392) +- Clean up unused Functions v1 code: FunctionsBilling.sol maxCallbackGasLimit & FunctionsRequest.sol requestSignature (#10509) +- Fix Functions v1 FunctionsBilling.sol gas price naming to reflect that it is in wei, not gwei (#10509) +- Use Natspec comment lines in Functions v1 contracts (#10567) +- Functions v1 Subscriptions now require a minimum number of requests to release a deposit amount (#10513) +- Fix Functions v1 Subscriptions add consumer checks for when maximum consumers changes in contract configuration (#10511) +- Functions v1 Router no longer reverts during fulfillment on an invalid client (#10511) +- Functions v1 Coordinator oracleWithdrawAll checks for 0 balances (#10511) ## 0.7.1 - 2023-09-20 @@ -17,6 +46,7 @@ - Functions library uses solidty-cborutils CBOR v2.0.0 and ENS Buffer v0.1.0(#8485) - Gas optimization to AuthorizedOriginReceiverUpgradable by using EnumberableSet .values() - Remove support for inline secrets in Functions requests (#8847) +- Moved versioned directories to use v prefix ## 0.6.1 - 2023-02-06 diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 328c921545c..b477164a496 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -38,7 +38,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-ca67d15f4abd46394b324c50e21e66f306a1162d + foundryup --version nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b .PHONY: foundry-refresh foundry-refresh: foundry diff --git a/contracts/foundry-lib/forge-std b/contracts/foundry-lib/forge-std index 1d9650e9512..f73c73d2018 160000 --- a/contracts/foundry-lib/forge-std +++ b/contracts/foundry-lib/forge-std @@ -1 +1 @@ -Subproject commit 1d9650e951204a0ddce9ff89c32f1997984cef4d +Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 diff --git a/contracts/foundry-lib/openzeppelin-contracts b/contracts/foundry-lib/openzeppelin-contracts deleted file mode 160000 index 1a60b061d5b..00000000000 --- a/contracts/foundry-lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1a60b061d5bb809c3d7e4ee915c77a00b1eca95d diff --git a/contracts/foundry.toml b/contracts/foundry.toml index d1bec52c391..1228ce3ec03 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -33,13 +33,18 @@ optimizer_runs = 10000 src = 'src/v0.8/automation' test = 'src/v0.8/automation/test' +[profile.l2ep] +optimizer_runs = 1000000 +src = 'src/v0.8/l2ep' +test = 'src/v0.8/l2ep/test' + + [profile.llo-feeds] optimizer_runs = 1000000 src = 'src/v0.8/llo-feeds' test = 'src/v0.8/llo-feeds/test' solc_version = '0.8.16' -# We cannot turn on deny_warnings = true as that will -# hide any CI failure +# We cannot turn on deny_warnings = true as that will hide any CI failure [profile.shared] optimizer_runs = 1000000 diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 0664a2eb997..b6298350604 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,7 +1,13 @@ FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32391) -FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53002) -FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13274) -FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 146635) +FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53182) +FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 53285) +FunctionsBilling_GetConfig:test_GetConfig_Success() (gas: 23671) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13296) +FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 146657) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 498113) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 199261) +FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 54991) +FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 11933) FunctionsOracle_sendRequest:testEmptyRequestDataReverts() (gas: 13452) FunctionsOracle_setDONPublicKey:testEmptyPublicKeyReverts() (gas: 10974) FunctionsOracle_setDONPublicKey:testOnlyOwnerReverts() (gas: 11255) @@ -12,18 +18,21 @@ FunctionsOracle_setRegistry:testOnlyOwnerReverts() (gas: 10927) FunctionsOracle_setRegistry:testSetRegistrySuccess() (gas: 35791) FunctionsOracle_setRegistry:testSetRegistry_gas() (gas: 31987) FunctionsOracle_typeAndVersion:testTypeAndVersionSuccess() (gas: 6905) +FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) +FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) +FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12073) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 172948) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 163234) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 169899) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 160226) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38092) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35224) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 181443) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 178394) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28063) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 156949) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 297578) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 311147) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2076842) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 515646) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 153900) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 296711) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 310303) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2484943) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 515428) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 18005) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12926) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37136) @@ -44,15 +53,15 @@ FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNe FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23369) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118456) FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59304) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192134) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192796) FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29405) FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57926) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 185987) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186209) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50902) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25061) FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29111) FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34247) -FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 197669) +FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 284999) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65800) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 35991) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29897) @@ -60,8 +69,8 @@ FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalid FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27482) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35696) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40766) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 204227) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192506) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 291551) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192728) FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30687) FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13380) FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13337) @@ -74,7 +83,7 @@ FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOw FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60962) FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94675) FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62691) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 59679) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 214576) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137833) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164777) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12926) @@ -86,27 +95,28 @@ FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubs FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57929) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89316) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20191) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193277) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 113352) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 124604) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 310123) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193763) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114636) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125891) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessRecieveDeposit() (gas: 311486) FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28637) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17948) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 371980) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351723) FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16225) -FunctionsSubscriptions_GetFlags:test_GetFlags_Success() (gas: 40858) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13100) +FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40858) FunctionsSubscriptions_GetSubscription:test_GetSubscription_Success() (gas: 30959) FunctionsSubscriptions_GetSubscriptionCount:test_GetSubscriptionCount_Success() (gas: 12967) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 14949) -FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 11863) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfEndIsAfterLastSubscription() (gas: 16523) +FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13436) FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59568) FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15032) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 27594) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 30071) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13402) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 35000) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success() (gas: 56279) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 28401, ~: 28401) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 30913, ~: 30913) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14248, ~: 14248) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 35870, ~: 35870) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 59685, ~: 59685) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) @@ -116,32 +126,34 @@ FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_SuccessSetsBalanceToZe FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNoSubscription() (gas: 12818) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15549) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 48362) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49624) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 163911) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 164300) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 165) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 210) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15533) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfNoAmount() (gas: 37396) -FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54435) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfRecipientAddressZero() (gas: 52130) +FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54413) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 15025) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175411) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175897) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27610) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57707) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15000) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75130) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17959) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20104) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68216) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68217) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82791) FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15532) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41093) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256, μ: 41699, ~: 41704) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30238) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 14997) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57778) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87186) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18004) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 190709) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191195) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12847) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15640) @@ -149,19 +161,20 @@ FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35549) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (gas: 25910) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25239) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28220) -FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57730) +FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57752) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26368) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15714) FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152510) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94815) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25837) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44348) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23597) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1458254) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866530) FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26003) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1538373) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 94684) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946591) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 104851) FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) -FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 50421) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 51794) FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12187) FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19243) FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15773) @@ -173,4 +186,10 @@ FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTru FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13525) FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95184) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13727) -FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) \ No newline at end of file +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) +Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84675) +Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79067) +Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73353) +Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38501) +Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 964209) +Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 156929) \ No newline at end of file diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index 74b9a9f9258..a9877fbe33c 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -20,7 +20,7 @@ FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 459 FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17546) FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54241) FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49252) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 11286) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12152) FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41348) FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 172711) FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 68984) @@ -87,7 +87,7 @@ FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 46503) FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49585) FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 77890) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14042) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14908) RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153306) RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328345) @@ -123,7 +123,7 @@ RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() ( RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576289) RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63555) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) -RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 11107) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) @@ -181,11 +181,11 @@ VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange( VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59967) VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1815769) VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) -VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 111727) +VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) -VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 68305) +VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 205796) -VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 110688) +VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 112334) VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1482522) VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1462646) VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) @@ -207,7 +207,7 @@ VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12720) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 201609) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 115615) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 117256) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538896) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964726) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520480) @@ -230,17 +230,17 @@ VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 317892) VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 324958) VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 86566) -VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 126411) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) +VerifierVerifyMultipleConfigDigestTest:test_revertsIfVerifyingWithAnUnsetDigest() (gas: 128062) VerifierVerifySingleConfigDigestTest:test_emitsAnEventIfReportVerified() (gas: 186945) VerifierVerifySingleConfigDigestTest:test_returnsThePriceAndBlockNumIfReportVerified() (gas: 187114) -VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 114479) -VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 180665) -VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 51479) -VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 102318) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 99348) -VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 182416) -VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 108382) +VerifierVerifySingleConfigDigestTest:test_revertsIfConfigDigestNotSet() (gas: 116130) +VerifierVerifySingleConfigDigestTest:test_revertsIfDuplicateSignersHaveSigned() (gas: 182315) +VerifierVerifySingleConfigDigestTest:test_revertsIfMismatchedSignatureLength() (gas: 53037) +VerifierVerifySingleConfigDigestTest:test_revertsIfReportHasUnconfiguredFeedID() (gas: 103976) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 100992) +VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) +VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 212066) Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 519368) diff --git a/contracts/package.json b/contracts/package.json index 750eaca181a..6c902926c2b 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,6 +1,6 @@ { "name": "@chainlink/contracts", - "version": "0.7.1", + "version": "0.8.0", "description": "Chainlink smart contracts", "author": "Chainlink devs", "license": "MIT", @@ -17,11 +17,12 @@ "coverage": "hardhat coverage", "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", - "publish-prod": "npm dist-tag add @chainlink/contracts@0.7.1 latest" + "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", + "solhint": "solhint --max-warnings 442 \"./src/v0.8/**/*.sol\"" }, "files": [ - "src/", - "abi/" + "src/v0.8", + "abi/src/v0.8" ], "pnpm": { "_comment": "See https://github.com/ethers-io/ethers.js/discussions/2849#discussioncomment-2696454", @@ -31,38 +32,38 @@ } }, "devDependencies": { - "@ethereum-waffle/mock-contract": "^3.3.0", + "@ethereum-waffle/mock-contract": "^3.4.4", "@ethersproject/abi": "~5.7.0", "@ethersproject/bignumber": "~5.7.0", "@ethersproject/contracts": "~5.7.0", "@ethersproject/providers": "~5.7.2", "@ethersproject/random": "~5.7.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.8", + "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.0", - "@nomiclabs/hardhat-waffle": "^2.0.1", - "@openzeppelin/hardhat-upgrades": "1.22.1", - "@openzeppelin/test-helpers": "^0.5.11", - "@typechain/ethers-v5": "^7.0.1", - "@typechain/hardhat": "^3.0.0", + "@nomiclabs/hardhat-waffle": "2.0.6", + "@openzeppelin/hardhat-upgrades": "1.28.0", + "@openzeppelin/test-helpers": "^0.5.16", + "@typechain/ethers-v5": "^7.2.0", + "@typechain/hardhat": "^5.0.0", "@types/cbor": "5.0.1", - "@types/chai": "^4.3.6", - "@types/debug": "^4.1.8", - "@types/deep-equal-in-any-order": "^1.0.1", - "@types/mocha": "^10.0.1", - "@types/node": "^16.18.52", - "@typescript-eslint/eslint-plugin": "^6.7.0", - "@typescript-eslint/parser": "^6.7.0", + "@types/chai": "^4.3.9", + "@types/debug": "^4.1.10", + "@types/deep-equal-in-any-order": "^1.0.2", + "@types/mocha": "^10.0.3", + "@types/node": "^16.18.58", + "@typescript-eslint/eslint-plugin": "^6.8.0", + "@typescript-eslint/parser": "^6.8.0", "abi-to-sol": "^0.6.6", - "chai": "^4.3.8", + "chai": "^4.3.10", "debug": "^4.3.4", - "eslint": "^8.49.0", + "eslint": "^8.51.0", "eslint-config-prettier": "^9.0.0", "deep-equal-in-any-order": "^2.0.6", - "eslint-plugin-prettier": "^5.0.0", - "ethereum-waffle": "^3.3.0", - "ethers": "~5.6.0", - "hardhat": "~2.17.3", + "eslint-plugin-prettier": "^5.0.1", + "ethereum-waffle": "^3.4.4", + "ethers": "~5.7.2", + "hardhat": "~2.18.1", "hardhat-abi-exporter": "^2.2.1", "hardhat-contract-sizer": "^2.5.1", "hardhat-gas-reporter": "^1.0.9", @@ -73,17 +74,17 @@ "prettier-plugin-solidity": "1.1.3", "rlp": "^2.2.7", "solhint": "^3.6.2", + "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git", "solhint-plugin-prettier": "^0.0.5", - "solidity-coverage": "^0.8.4", + "solidity-coverage": "^0.8.5", "ts-node": "^10.9.1", "tslib": "^2.6.2", "typechain": "^8.2.0", "typescript": "^5.2.2" }, "dependencies": { - "@eth-optimism/contracts": "^0.5.21", - "@openzeppelin/contracts": "~4.3.3", - "@openzeppelin/contracts-upgradeable-4.7.3": "npm:@openzeppelin/contracts-upgradeable@v4.7.3", - "@openzeppelin/contracts-v0.7": "npm:@openzeppelin/contracts@v3.4.2" + "@eth-optimism/contracts": "0.5.37", + "@openzeppelin/contracts": "4.9.3", + "@openzeppelin/contracts-upgradeable": "4.9.3" } } diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index b7179be4c60..9d54cfa7743 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -9,21 +9,18 @@ overrides: dependencies: '@eth-optimism/contracts': - specifier: ^0.5.21 - version: 0.5.37(ethers@5.6.1) + specifier: 0.5.37 + version: 0.5.37(ethers@5.7.2) '@openzeppelin/contracts': - specifier: ~4.3.3 - version: 4.3.3 - '@openzeppelin/contracts-upgradeable-4.7.3': - specifier: npm:@openzeppelin/contracts-upgradeable@v4.7.3 - version: /@openzeppelin/contracts-upgradeable@4.7.3 - '@openzeppelin/contracts-v0.7': - specifier: npm:@openzeppelin/contracts@v3.4.2 - version: /@openzeppelin/contracts@3.4.2 + specifier: 4.9.3 + version: 4.9.3 + '@openzeppelin/contracts-upgradeable': + specifier: 4.9.3 + version: 4.9.3 devDependencies: '@ethereum-waffle/mock-contract': - specifier: ^3.3.0 + specifier: ^3.4.4 version: 3.4.4 '@ethersproject/abi': specifier: ~5.7.0 @@ -41,59 +38,59 @@ devDependencies: specifier: ~5.7.0 version: 5.7.0 '@nomicfoundation/hardhat-network-helpers': - specifier: ^1.0.8 - version: 1.0.8(hardhat@2.17.3) + specifier: ^1.0.9 + version: 1.0.9(hardhat@2.18.1) '@nomiclabs/hardhat-ethers': specifier: ^2.2.3 - version: 2.2.3(ethers@5.6.1)(hardhat@2.17.3) + version: 2.2.3(ethers@5.7.2)(hardhat@2.18.1) '@nomiclabs/hardhat-etherscan': specifier: ^3.1.0 - version: 3.1.0(hardhat@2.17.3) + version: 3.1.0(hardhat@2.18.1) '@nomiclabs/hardhat-waffle': - specifier: ^2.0.1 - version: 2.0.1(@nomiclabs/hardhat-ethers@2.2.3)(ethereum-waffle@3.3.0)(ethers@5.6.1)(hardhat@2.17.3) + specifier: 2.0.6 + version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.18.1) '@openzeppelin/hardhat-upgrades': - specifier: 1.22.1 - version: 1.22.1(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.6.1)(hardhat@2.17.3) + specifier: 1.28.0 + version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.7.2)(hardhat@2.18.1) '@openzeppelin/test-helpers': - specifier: ^0.5.11 - version: 0.5.11(bn.js@4.12.0) + specifier: ^0.5.16 + version: 0.5.16(bn.js@4.12.0) '@typechain/ethers-v5': - specifier: ^7.0.1 - version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.6.1)(typechain@8.2.0)(typescript@5.2.2) + specifier: ^7.2.0 + version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2) '@typechain/hardhat': - specifier: ^3.0.0 - version: 3.1.0(hardhat@2.17.3)(lodash@4.17.21)(typechain@8.2.0) + specifier: ^5.0.0 + version: 5.0.0(hardhat@2.18.1)(lodash@4.17.21)(typechain@8.2.0) '@types/cbor': specifier: 5.0.1 version: 5.0.1 '@types/chai': - specifier: ^4.3.6 - version: 4.3.6 + specifier: ^4.3.9 + version: 4.3.9 '@types/debug': - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^4.1.10 + version: 4.1.10 '@types/deep-equal-in-any-order': - specifier: ^1.0.1 - version: 1.0.1 + specifier: ^1.0.2 + version: 1.0.2 '@types/mocha': - specifier: ^10.0.1 - version: 10.0.1 + specifier: ^10.0.3 + version: 10.0.3 '@types/node': - specifier: ^16.18.52 - version: 16.18.52 + specifier: ^16.18.58 + version: 16.18.58 '@typescript-eslint/eslint-plugin': - specifier: ^6.7.0 - version: 6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.2.2) + specifier: ^6.8.0 + version: 6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': - specifier: ^6.7.0 - version: 6.7.0(eslint@8.49.0)(typescript@5.2.2) + specifier: ^6.8.0 + version: 6.8.0(eslint@8.51.0)(typescript@5.2.2) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 chai: - specifier: ^4.3.8 - version: 4.3.8 + specifier: ^4.3.10 + version: 4.3.10 debug: specifier: ^4.3.4 version: 4.3.4(supports-color@8.1.1) @@ -101,32 +98,32 @@ devDependencies: specifier: ^2.0.6 version: 2.0.6 eslint: - specifier: ^8.49.0 - version: 8.49.0 + specifier: ^8.51.0 + version: 8.51.0 eslint-config-prettier: specifier: ^9.0.0 - version: 9.0.0(eslint@8.49.0) + version: 9.0.0(eslint@8.51.0) eslint-plugin-prettier: - specifier: ^5.0.0 - version: 5.0.0(eslint-config-prettier@9.0.0)(eslint@8.49.0)(prettier@3.0.3) + specifier: ^5.0.1 + version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.51.0)(prettier@3.0.3) ethereum-waffle: - specifier: ^3.3.0 - version: 3.3.0(typescript@5.2.2) + specifier: ^3.4.4 + version: 3.4.4(typescript@5.2.2) ethers: - specifier: ~5.6.0 - version: 5.6.1 + specifier: ~5.7.2 + version: 5.7.2 hardhat: - specifier: ~2.17.3 - version: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + specifier: ~2.18.1 + version: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) hardhat-abi-exporter: specifier: ^2.2.1 - version: 2.2.1(hardhat@2.17.3) + version: 2.2.1(hardhat@2.18.1) hardhat-contract-sizer: specifier: ^2.5.1 - version: 2.5.1(hardhat@2.17.3) + version: 2.5.1(hardhat@2.18.1) hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.9(hardhat@2.17.3) + version: 1.0.9(hardhat@2.18.1) hardhat-ignore-warnings: specifier: ^0.2.6 version: 0.2.9 @@ -148,15 +145,18 @@ devDependencies: solhint: specifier: ^3.6.2 version: 3.6.2 + solhint-plugin-chainlink-solidity: + specifier: git+https://github.com/smartcontractkit/chainlink-solhint-rules.git + version: github.com/smartcontractkit/chainlink-solhint-rules/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2 solhint-plugin-prettier: specifier: ^0.0.5 version: 0.0.5(prettier-plugin-solidity@1.1.3)(prettier@3.0.3) solidity-coverage: - specifier: ^0.8.4 - version: 0.8.4(hardhat@2.17.3) + specifier: ^0.8.5 + version: 0.8.5(hardhat@2.18.1) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@16.18.52)(typescript@5.2.2) + version: 10.9.1(@types/node@16.18.58)(typescript@5.2.2) tslib: specifier: ^2.6.2 version: 2.6.2 @@ -174,6 +174,36 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@aws-crypto/sha256-js@1.2.2: + resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} + dependencies: + '@aws-crypto/util': 1.2.2 + '@aws-sdk/types': 3.428.0 + tslib: 1.14.1 + dev: true + + /@aws-crypto/util@1.2.2: + resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} + dependencies: + '@aws-sdk/types': 3.428.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + dev: true + + /@aws-sdk/types@3.428.0: + resolution: {integrity: sha512-4T0Ps2spjg3qbWE6ZK13Vd3FnzpfliaiotqjxUK5YhjDrKXeT36HJp46JhDupElQuHtTkpdiJOSYk2lvY2H4IA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/types': 2.3.5 + tslib: 2.6.2 + dev: true + + /@aws-sdk/util-utf8-browser@3.259.0: + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + dependencies: + tslib: 2.6.2 + dev: true + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -279,7 +309,7 @@ packages: '@ensdomains/resolver': 0.2.4 content-hash: 2.5.2 eth-ens-namehash: 2.0.8 - ethers: 5.6.1 + ethers: 5.7.2 js-sha3: 0.8.0 transitivePeerDependencies: - bufferutil @@ -291,13 +321,13 @@ packages: deprecated: Please use @ensdomains/ens-contracts dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.49.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.51.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.49.0 + eslint: 8.51.0 eslint-visitor-keys: 3.4.3 dev: true @@ -323,12 +353,12 @@ packages: - supports-color dev: true - /@eslint/js@8.49.0: - resolution: {integrity: sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==} + /@eslint/js@8.51.0: + resolution: {integrity: sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@eth-optimism/contracts@0.5.37(ethers@5.6.1): + /@eth-optimism/contracts@0.5.37(ethers@5.7.2): resolution: {integrity: sha512-HbNUUDIM1dUAM0hWPfGp3l9/Zte40zi8QhVbUSIwdYRA7jG7cZgbteqavrjW8wwFqxkWX9IrtA0KAR7pNlSAIQ==} peerDependencies: ethers: ^5 @@ -336,7 +366,7 @@ packages: '@eth-optimism/core-utils': 0.10.1 '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 - ethers: 5.6.1 + ethers: 5.7.2 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -360,7 +390,7 @@ packages: '@ethersproject/transactions': 5.7.0 '@ethersproject/web': 5.7.1 bufio: 1.0.7 - chai: 4.3.8 + chai: 4.3.10 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -371,7 +401,7 @@ packages: engines: {node: '>=10.0'} dependencies: '@ethereum-waffle/provider': 3.4.4 - ethers: 5.6.1 + ethers: 5.7.2 transitivePeerDependencies: - bufferutil - encoding @@ -385,10 +415,10 @@ packages: dependencies: '@resolver-engine/imports': 0.3.3 '@resolver-engine/imports-fs': 0.3.3 - '@typechain/ethers-v5': 2.0.0(ethers@5.6.1)(typechain@3.0.0) + '@typechain/ethers-v5': 2.0.0(ethers@5.7.2)(typechain@3.0.0) '@types/mkdirp': 0.5.2 '@types/node-fetch': 2.6.2 - ethers: 5.6.1 + ethers: 5.7.2 mkdirp: 0.5.6 node-fetch: 2.6.7 solc: 0.6.12 @@ -408,7 +438,7 @@ packages: dependencies: '@ensdomains/ens': 0.4.5 '@ensdomains/resolver': 0.2.4 - ethers: 5.6.1 + ethers: 5.7.2 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -419,7 +449,7 @@ packages: engines: {node: '>=10.0'} dependencies: '@ethersproject/abi': 5.7.0 - ethers: 5.6.1 + ethers: 5.7.2 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -430,9 +460,9 @@ packages: engines: {node: '>=10.0'} dependencies: '@ethereum-waffle/ens': 3.4.4 - ethers: 5.6.1 + ethers: 5.7.2 ganache-core: 2.13.2 - patch-package: 6.4.7 + patch-package: 6.5.1 postinstall-postinstall: 2.1.0 transitivePeerDependencies: - bufferutil @@ -471,19 +501,6 @@ packages: dev: true optional: true - /@ethersproject/abi@5.6.0: - resolution: {integrity: sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg==} - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - /@ethersproject/abi@5.7.0: resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} dependencies: @@ -497,17 +514,6 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - /@ethersproject/abstract-provider@5.6.0: - resolution: {integrity: sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - /@ethersproject/abstract-provider@5.7.0: resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} dependencies: @@ -519,15 +525,6 @@ packages: '@ethersproject/transactions': 5.7.0 '@ethersproject/web': 5.7.1 - /@ethersproject/abstract-signer@5.6.0: - resolution: {integrity: sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - /@ethersproject/abstract-signer@5.7.0: resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} dependencies: @@ -537,15 +534,6 @@ packages: '@ethersproject/logger': 5.0.6 '@ethersproject/properties': 5.7.0 - /@ethersproject/address@5.6.0: - resolution: {integrity: sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/rlp': 5.7.0 - /@ethersproject/address@5.7.0: resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} dependencies: @@ -555,35 +543,17 @@ packages: '@ethersproject/logger': 5.0.6 '@ethersproject/rlp': 5.7.0 - /@ethersproject/base64@5.6.0: - resolution: {integrity: sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - /@ethersproject/base64@5.7.0: resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} dependencies: '@ethersproject/bytes': 5.7.0 - /@ethersproject/basex@5.6.0: - resolution: {integrity: sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/properties': 5.7.0 - /@ethersproject/basex@5.7.0: resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/properties': 5.7.0 - /@ethersproject/bignumber@5.6.0: - resolution: {integrity: sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - bn.js: 4.12.0 - /@ethersproject/bignumber@5.7.0: resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} dependencies: @@ -591,40 +561,16 @@ packages: '@ethersproject/logger': 5.0.6 bn.js: 5.2.1 - /@ethersproject/bytes@5.6.0: - resolution: {integrity: sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==} - dependencies: - '@ethersproject/logger': 5.0.6 - /@ethersproject/bytes@5.7.0: resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} dependencies: '@ethersproject/logger': 5.0.6 - /@ethersproject/constants@5.6.0: - resolution: {integrity: sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - /@ethersproject/constants@5.7.0: resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} dependencies: '@ethersproject/bignumber': 5.7.0 - /@ethersproject/contracts@5.6.0: - resolution: {integrity: sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==} - dependencies: - '@ethersproject/abi': 5.7.0 - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/transactions': 5.7.0 - /@ethersproject/contracts@5.7.0: resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} dependencies: @@ -639,18 +585,6 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/transactions': 5.7.0 - /@ethersproject/hash@5.6.0: - resolution: {integrity: sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - /@ethersproject/hash@5.7.0: resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} dependencies: @@ -664,22 +598,6 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - /@ethersproject/hdnode@5.6.0: - resolution: {integrity: sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 - /@ethersproject/hdnode@5.7.0: resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} dependencies: @@ -696,23 +614,6 @@ packages: '@ethersproject/transactions': 5.7.0 '@ethersproject/wordlists': 5.7.0 - /@ethersproject/json-wallets@5.6.0: - resolution: {integrity: sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==} - dependencies: - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/pbkdf2': 5.7.0 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - aes-js: 3.0.0 - scrypt-js: 3.0.1 - /@ethersproject/json-wallets@5.7.0: resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} dependencies: @@ -730,12 +631,6 @@ packages: aes-js: 3.0.0 scrypt-js: 3.0.1 - /@ethersproject/keccak256@5.6.0: - resolution: {integrity: sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==} - dependencies: - '@ethersproject/bytes': 5.7.0 - js-sha3: 0.8.0 - /@ethersproject/keccak256@5.7.0: resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} dependencies: @@ -745,64 +640,22 @@ packages: /@ethersproject/logger@5.0.6: resolution: {integrity: sha512-FrX0Vnb3JZ1md/7GIZfmJ06XOAA8r3q9Uqt9O5orr4ZiksnbpXKlyDzQtlZ5Yv18RS8CAUbiKH9vwidJg1BPmQ==} - /@ethersproject/networks@5.6.0: - resolution: {integrity: sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ==} - dependencies: - '@ethersproject/logger': 5.0.6 - /@ethersproject/networks@5.7.1: resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} dependencies: '@ethersproject/logger': 5.0.6 - /@ethersproject/pbkdf2@5.6.0: - resolution: {integrity: sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/sha2': 5.7.0 - /@ethersproject/pbkdf2@5.7.0: resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/sha2': 5.7.0 - /@ethersproject/properties@5.6.0: - resolution: {integrity: sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==} - dependencies: - '@ethersproject/logger': 5.0.6 - /@ethersproject/properties@5.7.0: resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} dependencies: '@ethersproject/logger': 5.0.6 - /@ethersproject/providers@5.6.1: - resolution: {integrity: sha512-w8Wx15nH+aVDvnoKCyI1f3x0B5idmk/bDJXMEUqCfdO8Eadd0QpDx9lDMTMmenhOmf9vufLJXjpSm24D3ZnVpg==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/basex': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/networks': 5.7.1 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/web': 5.7.1 - bech32: 1.1.4 - ws: 7.4.6 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - /@ethersproject/providers@5.7.2: resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} dependencies: @@ -830,37 +683,18 @@ packages: - bufferutil - utf-8-validate - /@ethersproject/random@5.6.0: - resolution: {integrity: sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - /@ethersproject/random@5.7.0: resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.0.6 - /@ethersproject/rlp@5.6.0: - resolution: {integrity: sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - /@ethersproject/rlp@5.7.0: resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.0.6 - /@ethersproject/sha2@5.6.0: - resolution: {integrity: sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - hash.js: 1.1.7 - /@ethersproject/sha2@5.7.0: resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} dependencies: @@ -868,16 +702,6 @@ packages: '@ethersproject/logger': 5.0.6 hash.js: 1.1.7 - /@ethersproject/signing-key@5.6.0: - resolution: {integrity: sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - bn.js: 4.12.0 - elliptic: 6.5.4 - hash.js: 1.1.7 - /@ethersproject/signing-key@5.7.0: resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} dependencies: @@ -888,16 +712,6 @@ packages: elliptic: 6.5.4 hash.js: 1.1.7 - /@ethersproject/solidity@5.6.0: - resolution: {integrity: sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/sha2': 5.7.0 - '@ethersproject/strings': 5.7.0 - /@ethersproject/solidity@5.7.0: resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} dependencies: @@ -907,14 +721,6 @@ packages: '@ethersproject/logger': 5.0.6 '@ethersproject/sha2': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - - /@ethersproject/strings@5.6.0: - resolution: {integrity: sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.0.6 /@ethersproject/strings@5.7.0: resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} @@ -923,19 +729,6 @@ packages: '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.0.6 - /@ethersproject/transactions@5.6.0: - resolution: {integrity: sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==} - dependencies: - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/rlp': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - /@ethersproject/transactions@5.7.0: resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} dependencies: @@ -949,39 +742,12 @@ packages: '@ethersproject/rlp': 5.7.0 '@ethersproject/signing-key': 5.7.0 - /@ethersproject/units@5.6.0: - resolution: {integrity: sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==} - dependencies: - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/constants': 5.7.0 - '@ethersproject/logger': 5.0.6 - /@ethersproject/units@5.7.0: resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} dependencies: '@ethersproject/bignumber': 5.7.0 '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.0.6 - dev: true - - /@ethersproject/wallet@5.6.0: - resolution: {integrity: sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==} - dependencies: - '@ethersproject/abstract-provider': 5.7.0 - '@ethersproject/abstract-signer': 5.7.0 - '@ethersproject/address': 5.7.0 - '@ethersproject/bignumber': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/hdnode': 5.7.0 - '@ethersproject/json-wallets': 5.7.0 - '@ethersproject/keccak256': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/random': 5.7.0 - '@ethersproject/signing-key': 5.7.0 - '@ethersproject/transactions': 5.7.0 - '@ethersproject/wordlists': 5.7.0 /@ethersproject/wallet@5.7.0: resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} @@ -1001,16 +767,6 @@ packages: '@ethersproject/signing-key': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/wordlists': 5.7.0 - dev: true - - /@ethersproject/web@5.6.0: - resolution: {integrity: sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==} - dependencies: - '@ethersproject/base64': 5.7.0 - '@ethersproject/bytes': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 /@ethersproject/web@5.7.1: resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} @@ -1021,15 +777,6 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - /@ethersproject/wordlists@5.6.0: - resolution: {integrity: sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==} - dependencies: - '@ethersproject/bytes': 5.7.0 - '@ethersproject/hash': 5.7.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/properties': 5.7.0 - '@ethersproject/strings': 5.7.0 - /@ethersproject/wordlists@5.7.0: resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} dependencies: @@ -1068,11 +815,25 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@ljharb/resumer@0.0.1: + resolution: {integrity: sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==} + engines: {node: '>= 0.4'} + dependencies: + '@ljharb/through': 2.3.11 + dev: true + + /@ljharb/through@2.3.11: + resolution: {integrity: sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==} + engines: {node: '>= 0.4'} dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + call-bind: 1.0.2 dev: true /@metamask/eth-sig-util@4.0.1: @@ -1273,13 +1034,13 @@ packages: - utf-8-validate dev: true - /@nomicfoundation/hardhat-network-helpers@1.0.8(hardhat@2.17.3): - resolution: {integrity: sha512-MNqQbzUJZnCMIYvlniC3U+kcavz/PhhQSsY90tbEtUyMj/IQqsLwIRZa4ctjABh3Bz0KCh9OXUZ7Yk/d9hr45Q==} + /@nomicfoundation/hardhat-network-helpers@1.0.9(hardhat@2.18.1): + resolution: {integrity: sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==} peerDependencies: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0: @@ -1388,17 +1149,17 @@ packages: '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.0 dev: true - /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.6.1)(hardhat@2.17.3): + /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.18.1): resolution: {integrity: sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==} peerDependencies: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: - ethers: 5.6.1 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + ethers: 5.7.2 + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /@nomiclabs/hardhat-etherscan@3.1.0(hardhat@2.17.3): + /@nomiclabs/hardhat-etherscan@3.1.0(hardhat@2.18.1): resolution: {integrity: sha512-JroYgfN1AlYFkQTQ3nRwFi4o8NtZF7K/qFR2dxDUgHbCtIagkUseca9L4E/D2ScUm4XT40+8PbCdqZi+XmHyQA==} peerDependencies: hardhat: ^2.0.4 @@ -1409,7 +1170,7 @@ packages: chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) lodash: 4.17.21 semver: 6.3.0 table: 6.8.0 @@ -1418,20 +1179,20 @@ packages: - supports-color dev: true - /@nomiclabs/hardhat-waffle@2.0.1(@nomiclabs/hardhat-ethers@2.2.3)(ethereum-waffle@3.3.0)(ethers@5.6.1)(hardhat@2.17.3): - resolution: {integrity: sha512-2YR2V5zTiztSH9n8BYWgtv3Q+EL0N5Ltm1PAr5z20uAY4SkkfylJ98CIqt18XFvxTD5x4K2wKBzddjV9ViDAZQ==} + /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.18.1): + resolution: {integrity: sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg==} peerDependencies: '@nomiclabs/hardhat-ethers': ^2.0.0 - ethereum-waffle: ^3.2.0 + '@types/sinon-chai': ^3.2.3 + ethereum-waffle: '*' ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.6.1)(hardhat@2.17.3) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.18.1) '@types/sinon-chai': 3.2.8 - '@types/web3': 1.0.19 - ethereum-waffle: 3.3.0(typescript@5.2.2) - ethers: 5.6.1 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + ethereum-waffle: 3.4.4(typescript@5.2.2) + ethers: 5.7.2 + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true /@openzeppelin/contract-loader@0.6.3: @@ -1441,20 +1202,29 @@ packages: fs-extra: 8.1.0 dev: true - /@openzeppelin/contracts-upgradeable@4.7.3: - resolution: {integrity: sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A==} + /@openzeppelin/contracts-upgradeable@4.9.3: + resolution: {integrity: sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A==} dev: false - /@openzeppelin/contracts@3.4.2: - resolution: {integrity: sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA==} + /@openzeppelin/contracts@4.9.3: + resolution: {integrity: sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg==} dev: false - /@openzeppelin/contracts@4.3.3: - resolution: {integrity: sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g==} - dev: false + /@openzeppelin/defender-base-client@1.49.0(debug@4.3.4): + resolution: {integrity: sha512-nG2jslaAUbo2ZW9yBStstxTPscAchN/vRdJ16M34whuZRtUp1bccCBVLdv3oiPOdjwFaa1OBXJkheN+eF8alzA==} + dependencies: + amazon-cognito-identity-js: 6.3.6 + async-retry: 1.3.3 + axios: 1.5.1(debug@4.3.4) + lodash: 4.17.21 + node-fetch: 2.6.7 + transitivePeerDependencies: + - debug + - encoding + dev: true - /@openzeppelin/hardhat-upgrades@1.22.1(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.6.1)(hardhat@2.17.3): - resolution: {integrity: sha512-MdoitCTLl4zwMU8MeE/bCj+7JMWBEvd38XqJkw36PkJrXlbv6FedDVCPoumMAhpmtymm0nTwTYYklYG+L6WiiQ==} + /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.0)(ethers@5.7.2)(hardhat@2.18.1): + resolution: {integrity: sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==} hasBin: true peerDependencies: '@nomiclabs/hardhat-ethers': ^2.0.0 @@ -1466,26 +1236,43 @@ packages: '@nomiclabs/harhdat-etherscan': optional: true dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.6.1)(hardhat@2.17.3) - '@nomiclabs/hardhat-etherscan': 3.1.0(hardhat@2.17.3) - '@openzeppelin/upgrades-core': 1.22.0 + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.18.1) + '@nomiclabs/hardhat-etherscan': 3.1.0(hardhat@2.18.1) + '@openzeppelin/defender-base-client': 1.49.0(debug@4.3.4) + '@openzeppelin/platform-deploy-client': 0.8.0(debug@4.3.4) + '@openzeppelin/upgrades-core': 1.30.1 chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) - ethers: 5.6.1 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + ethers: 5.7.2 + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) proper-lockfile: 4.1.2 transitivePeerDependencies: + - encoding - supports-color dev: true - /@openzeppelin/test-helpers@0.5.11(bn.js@4.12.0): - resolution: {integrity: sha512-HkFpCjtTD8dk+wdYhsT07YbMGCE+Z4Wp5sBKXvPDF3Lynoc0H2KqZgCWV+qr2YZ0WW1oX/sXkKFrrKJ0caBTjw==} + /@openzeppelin/platform-deploy-client@0.8.0(debug@4.3.4): + resolution: {integrity: sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA==} + deprecated: '@openzeppelin/platform-deploy-client is deprecated. Please use @openzeppelin/defender-sdk-deploy-client' + dependencies: + '@ethersproject/abi': 5.7.0 + '@openzeppelin/defender-base-client': 1.49.0(debug@4.3.4) + axios: 0.21.4(debug@4.3.4) + lodash: 4.17.21 + node-fetch: 2.6.7 + transitivePeerDependencies: + - debug + - encoding + dev: true + + /@openzeppelin/test-helpers@0.5.16(bn.js@4.12.0): + resolution: {integrity: sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==} dependencies: '@openzeppelin/contract-loader': 0.6.3 '@truffle/contract': 4.6.2 ansi-colors: 3.2.4 - chai: 4.3.8 - chai-bn: 0.2.2(bn.js@4.12.0)(chai@4.3.8) + chai: 4.3.10 + chai-bn: 0.2.2(bn.js@4.12.0)(chai@4.3.10) ethjs-abi: 0.2.1 lodash.flatten: 4.4.0 semver: 5.7.1 @@ -1499,16 +1286,18 @@ packages: - utf-8-validate dev: true - /@openzeppelin/upgrades-core@1.22.0: - resolution: {integrity: sha512-TcTabzRbYOzWJnwiToj0LRzje25d9QbDPe2dOT9eHlLDRhOMiep39FDibJjkYd5IdF3s8M9IcK+YSnf49renEg==} + /@openzeppelin/upgrades-core@1.30.1: + resolution: {integrity: sha512-mFUsZibpiWJv1DR2K89cjbFIseTc2CUV4D2kvPPK5xYke6m7+M87qcr/Xk24mMrdCmG7RWNxQohhVnzESI6Eeg==} + hasBin: true dependencies: - cbor: 8.1.0 + cbor: 9.0.1 chalk: 4.1.2 - compare-versions: 5.0.3 + compare-versions: 6.1.0 debug: 4.3.4(supports-color@8.1.1) ethereumjs-util: 7.1.5 + minimist: 1.2.8 proper-lockfile: 4.1.2 - solidity-ast: 0.4.45 + solidity-ast: 0.4.52 transitivePeerDependencies: - supports-color dev: true @@ -1666,6 +1455,13 @@ packages: engines: {node: '>=10'} dev: true + /@smithy/types@2.3.5: + resolution: {integrity: sha512-ehyDt8M9hehyxrLQGoA1BGPou8Js1Ocoh5M0ngDhJMqbFmNK5N6Xhr9/ZExWkyIW8XcGkiMPq3ZUEE0ScrhbuQ==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.2 + dev: true + /@solidity-parser/parser@0.14.3: resolution: {integrity: sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw==} dependencies: @@ -1819,17 +1615,17 @@ packages: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} dev: true - /@typechain/ethers-v5@2.0.0(ethers@5.6.1)(typechain@3.0.0): + /@typechain/ethers-v5@2.0.0(ethers@5.7.2)(typechain@3.0.0): resolution: {integrity: sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw==} peerDependencies: ethers: ^5.0.0 typechain: ^3.0.0 dependencies: - ethers: 5.6.1 + ethers: 5.7.2 typechain: 3.0.0(typescript@5.2.2) dev: true - /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.6.1)(typechain@8.2.0)(typescript@5.2.2): + /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.2.0)(typescript@5.2.2): resolution: {integrity: sha512-jfcmlTvaaJjng63QsT49MT6R1HFhtO/TBMWbyzPFSzMmVIqb2tL6prnKBs4ZJrSvmgIXWy+ttSjpaxCTq8D/Tw==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -1842,22 +1638,22 @@ packages: '@ethersproject/abi': 5.7.0 '@ethersproject/bytes': 5.7.0 '@ethersproject/providers': 5.7.2 - ethers: 5.6.1 + ethers: 5.7.2 lodash: 4.17.21 ts-essentials: 7.0.3(typescript@5.2.2) typechain: 8.2.0(typescript@5.2.2) typescript: 5.2.2 dev: true - /@typechain/hardhat@3.1.0(hardhat@2.17.3)(lodash@4.17.21)(typechain@8.2.0): - resolution: {integrity: sha512-C6Be6l+vTpao19PvMH2CB/lhL1TRLkhdPkvQCF/zqkY1e+0iqY2Bb9Jd3PTt6I8QvMm89ZDerrCJC9927ZHmlg==} + /@typechain/hardhat@5.0.0(hardhat@2.18.1)(lodash@4.17.21)(typechain@8.2.0): + resolution: {integrity: sha512-Pqk+KdREbU6Uk3en1Z5caQpWt2bKU+KTOi+6dZwcIXJpF1wKoAwF1cbaYSQEzrG4BSUTM1rHQhW5JHSfeqpsAg==} peerDependencies: hardhat: ^2.0.10 lodash: ^4.17.15 - typechain: ^6.0.0 + typechain: ^7.0.0 dependencies: fs-extra: 9.1.0 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) lodash: 4.17.21 typechain: 8.2.0(typescript@5.2.2) dev: true @@ -1865,13 +1661,13 @@ packages: /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/cacheable-request@6.0.2: @@ -1879,34 +1675,34 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 16.18.52 + '@types/node': 16.18.58 '@types/responselike': 1.0.0 dev: true /@types/cbor@5.0.1: resolution: {integrity: sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true - /@types/chai@4.3.6: - resolution: {integrity: sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==} + /@types/chai@4.3.9: + resolution: {integrity: sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg==} dev: true /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true - /@types/debug@4.1.8: - resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} + /@types/debug@4.1.10: + resolution: {integrity: sha512-tOSCru6s732pofZ+sMv9o4o3Zc+Sa8l3bxd/tweTQudFn06vAzb13ZX46Zi6m6EJ+RUbRTHvgQJ1gBtSgkaUYA==} dependencies: '@types/ms': 0.7.31 dev: true - /@types/deep-equal-in-any-order@1.0.1: - resolution: {integrity: sha512-hUWUUE53WjKfcCncSmWmNXVNNT+0Iz7gYFnov3zdCXrX3Thxp1Cnmfd5LwWOeCVUV5LhpiFgS05vaAG72doo9w==} + /@types/deep-equal-in-any-order@1.0.2: + resolution: {integrity: sha512-IUjUMsroT9qb8d7ySAl5V+iT/7UsJDpIFspTLxBWxCLqeJwwptSvmjvDBEEaZt0qodMyUSoOQkLhqZAkqt6dLg==} dev: true /@types/events@3.0.0: @@ -1916,7 +1712,7 @@ packages: /@types/form-data@0.0.33: resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/glob@7.1.1: @@ -1924,7 +1720,7 @@ packages: dependencies: '@types/events': 3.0.0 '@types/minimatch': 3.0.3 - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/http-cache-semantics@4.0.1: @@ -1938,7 +1734,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/lru-cache@5.1.1: @@ -1952,11 +1748,11 @@ packages: /@types/mkdirp@0.5.2: resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true - /@types/mocha@10.0.1: - resolution: {integrity: sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==} + /@types/mocha@10.0.3: + resolution: {integrity: sha512-RsOPImTriV/OE4A9qKjMtk2MnXiuLLbcO3nCXK+kvq4nr0iMfFgpjaX3MPLb6f7+EL1FGSelYvuJMV6REH+ZPQ==} dev: true /@types/ms@0.7.31: @@ -1966,7 +1762,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 form-data: 3.0.1 dev: true @@ -1978,8 +1774,8 @@ packages: resolution: {integrity: sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==} dev: true - /@types/node@16.18.52: - resolution: {integrity: sha512-sm2aph6cRSsTMFYFgI+RpPLunXO9ClJkpizUVdT7KmGeyfQ14xnjTMT/f3MHcfKqevXqGT6BgVFzW8wcEoDUtA==} + /@types/node@16.18.58: + resolution: {integrity: sha512-YGncyA25/MaVtQkjWW9r0EFBukZ+JulsLcVZBlGUfIb96OBMjkoRWwQo5IEWJ8Fj06Go3GHw+bjYDitv6BaGsA==} dev: true /@types/node@8.10.66: @@ -1989,7 +1785,7 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/prettier@2.7.1: @@ -2003,26 +1799,26 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 safe-buffer: 5.1.2 dev: true /@types/resolve@0.0.8: resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 16.18.52 + '@types/node': 16.18.58 dev: true /@types/semver@7.5.0: @@ -2032,7 +1828,7 @@ packages: /@types/sinon-chai@3.2.8: resolution: {integrity: sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g==} dependencies: - '@types/chai': 4.3.6 + '@types/chai': 4.3.9 '@types/sinon': 10.0.13 dev: true @@ -2046,19 +1842,8 @@ packages: resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} dev: true - /@types/underscore@1.11.4: - resolution: {integrity: sha512-uO4CD2ELOjw8tasUrAhvnn2W4A0ZECOvMjCivJr4gA9pGgjv+qxKWY9GLTMVEK8ej85BxQOocUyE7hImmSQYcg==} - dev: true - - /@types/web3@1.0.19: - resolution: {integrity: sha512-fhZ9DyvDYDwHZUp5/STa9XW2re0E8GxoioYJ4pEUZ13YHpApSagixj7IAdoYH5uAK+UalGq6Ml8LYzmgRA/q+A==} - dependencies: - '@types/bn.js': 5.1.1 - '@types/underscore': 1.11.4 - dev: true - - /@typescript-eslint/eslint-plugin@6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==} + /@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.8.0)(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -2069,13 +1854,13 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.7.0(eslint@8.49.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.7.0 - '@typescript-eslint/type-utils': 6.7.0(eslint@8.49.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.0(eslint@8.49.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.0 + '@typescript-eslint/parser': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/type-utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.49.0 + eslint: 8.51.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -2086,8 +1871,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.7.0(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng==} + /@typescript-eslint/parser@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2096,27 +1881,27 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.7.0 - '@typescript-eslint/types': 6.7.0 - '@typescript-eslint/typescript-estree': 6.7.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.7.0 + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.49.0 + eslint: 8.51.0 typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@6.7.0: - resolution: {integrity: sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA==} + /@typescript-eslint/scope-manager@6.8.0: + resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.0 - '@typescript-eslint/visitor-keys': 6.7.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 dev: true - /@typescript-eslint/type-utils@6.7.0(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==} + /@typescript-eslint/type-utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -2125,23 +1910,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.7.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.7.0(eslint@8.49.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.49.0 + eslint: 8.51.0 ts-api-utils: 1.0.3(typescript@5.2.2) typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@6.7.0: - resolution: {integrity: sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q==} + /@typescript-eslint/types@6.8.0: + resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.7.0(typescript@5.2.2): - resolution: {integrity: sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ==} + /@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): + resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -2149,8 +1934,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.7.0 - '@typescript-eslint/visitor-keys': 6.7.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/visitor-keys': 6.8.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 @@ -2161,30 +1946,30 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@6.7.0(eslint@8.49.0)(typescript@5.2.2): - resolution: {integrity: sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==} + /@typescript-eslint/utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): + resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.7.0 - '@typescript-eslint/types': 6.7.0 - '@typescript-eslint/typescript-estree': 6.7.0(typescript@5.2.2) - eslint: 8.49.0 + '@typescript-eslint/scope-manager': 6.8.0 + '@typescript-eslint/types': 6.8.0 + '@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) + eslint: 8.51.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@6.7.0: - resolution: {integrity: sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ==} + /@typescript-eslint/visitor-keys@6.8.0: + resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.7.0 + '@typescript-eslint/types': 6.8.0 eslint-visitor-keys: 3.4.3 dev: true @@ -2264,6 +2049,7 @@ packages: /accepts@1.3.7: resolution: {integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==} engines: {node: '>= 0.6'} + requiresBuild: true dependencies: mime-types: 2.1.27 negotiator: 0.6.2 @@ -2342,6 +2128,18 @@ packages: uri-js: 4.4.1 dev: true + /amazon-cognito-identity-js@6.3.6: + resolution: {integrity: sha512-kBq+GE6OkLrxtFj3ZduIOlKBFYeOqZK3EhxbDBkv476UTvy+uwfR0tlriTq2QzNdnvlQAjBIXnXuOM7DwR1UEQ==} + dependencies: + '@aws-crypto/sha256-js': 1.2.2 + buffer: 4.9.2 + fast-base64-decode: 1.0.0 + isomorphic-unfetch: 3.1.0 + js-cookie: 2.2.1 + transitivePeerDependencies: + - encoding + dev: true + /amdefine@1.0.1: resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} engines: {node: '>=0.4.2'} @@ -2485,12 +2283,16 @@ packages: engines: {node: '>=8'} dev: true - /array-filter@1.0.0: - resolution: {integrity: sha512-Ene1hbrinPZ1qPoZp7NSx4jQnh4nr7MtY78pHNb+yr8yHbxmTS7ChGW0a55JKA7TkRDeoQxK4GcJaCvBYplSKA==} + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.2 + is-array-buffer: 3.0.2 dev: true /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + requiresBuild: true dev: true /array-union@2.1.0: @@ -2508,6 +2310,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /array.prototype.findlast@1.2.3: + resolution: {integrity: sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.1 + dev: true + /array.prototype.reduce@1.0.4: resolution: {integrity: sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==} engines: {node: '>= 0.4'} @@ -2519,12 +2332,37 @@ packages: is-string: 1.0.7 dev: true + /array.prototype.reduce@1.0.6: + resolution: {integrity: sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + es-array-method-boxes-properly: 1.0.0 + is-string: 1.0.7 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + /asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} dev: true /asn1.js@4.10.1: resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + requiresBuild: true dependencies: bn.js: 4.12.0 inherits: 2.0.4 @@ -2569,6 +2407,12 @@ packages: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} dev: true + /async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + dependencies: + retry: 0.13.1 + dev: true + /async@1.5.2: resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} dev: true @@ -2600,11 +2444,9 @@ packages: hasBin: true dev: true - /available-typed-arrays@1.0.2: - resolution: {integrity: sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==} + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - dependencies: - array-filter: 1.0.0 dev: true /aws-sign2@0.7.0: @@ -2615,6 +2457,24 @@ packages: resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} dev: true + /axios@0.21.4(debug@4.3.4): + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + dependencies: + follow-redirects: 1.15.2(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: true + + /axios@1.5.1(debug@4.3.4): + resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} + dependencies: + follow-redirects: 1.15.2(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: true + /babel-code-frame@6.26.0: resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} dependencies: @@ -2636,7 +2496,7 @@ packages: babel-traverse: 6.26.0 babel-types: 6.26.0 babylon: 6.18.0 - convert-source-map: 1.8.0 + convert-source-map: 1.9.0 debug: 2.6.9 json5: 0.5.1 lodash: 4.17.21 @@ -3230,12 +3090,6 @@ packages: engines: {node: '>=8'} dev: true - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - dependencies: - file-uri-to-path: 1.0.0 - dev: true - /bip39@2.5.0: resolution: {integrity: sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==} dependencies: @@ -3246,12 +3100,6 @@ packages: unorm: 1.6.0 dev: true - /bip66@1.1.5: - resolution: {integrity: sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==} - dependencies: - safe-buffer: 5.2.1 - dev: true - /blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} dev: true @@ -3273,6 +3121,7 @@ packages: /body-parser@1.19.0: resolution: {integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==} engines: {node: '>= 0.8'} + requiresBuild: true dependencies: bytes: 3.1.0 content-type: 1.0.4 @@ -3366,6 +3215,7 @@ packages: /browserify-cipher@1.0.1: resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + requiresBuild: true dependencies: browserify-aes: 1.2.0 browserify-des: 1.0.2 @@ -3374,6 +3224,7 @@ packages: /browserify-des@1.0.2: resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + requiresBuild: true dependencies: cipher-base: 1.0.4 des.js: 1.0.1 @@ -3383,20 +3234,15 @@ packages: /browserify-rsa@4.0.1: resolution: {integrity: sha512-+YpEyaLDDvvdzIxQ+cCx73r5YEhS3ANGOkiHdyWqW4t3gdeoNEYjSiQwntbU4Uo2/9yRkpYX3SRFeH+7jc2Duw==} + requiresBuild: true dependencies: bn.js: 4.12.0 randombytes: 2.1.0 dev: true - /browserify-sha3@0.0.4: - resolution: {integrity: sha512-WmXX4M8lltqzMnBiPbP9KQdITknmxe4Wp3rhGfpYJst5yOeGwKkHpC0t+Ty22laH4Ltg9YO+p14p93wiipqjxA==} - dependencies: - js-sha3: 0.6.1 - safe-buffer: 5.2.1 - dev: true - /browserify-sign@4.0.4: resolution: {integrity: sha512-D2ItxCwNtLcHRrOCuEDZQlIezlFyUV/N5IYz6TY1svu1noyThFuthoEjzT8ChZe3UEctqnwmykcPhet3Eiz58A==} + requiresBuild: true dependencies: bn.js: 4.12.0 browserify-rsa: 4.0.1 @@ -3411,8 +3257,8 @@ packages: resolution: {integrity: sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==} hasBin: true dependencies: - caniuse-lite: 1.0.30001414 - electron-to-chromium: 1.4.270 + caniuse-lite: 1.0.30001549 + electron-to-chromium: 1.4.556 dev: true /bs58@4.0.1: @@ -3435,10 +3281,12 @@ packages: /buffer-to-arraybuffer@0.0.5: resolution: {integrity: sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==} + requiresBuild: true dev: true /buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + requiresBuild: true dev: true /buffer-xor@2.0.2: @@ -3447,6 +3295,14 @@ packages: safe-buffer: 5.2.1 dev: true + /buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + dev: true + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -3491,6 +3347,7 @@ packages: /bytes@3.1.0: resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} engines: {node: '>= 0.8'} + requiresBuild: true dev: true /bytes@3.1.2: @@ -3604,8 +3461,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001414: - resolution: {integrity: sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==} + /caniuse-lite@1.0.30001549: + resolution: {integrity: sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==} dev: true /case@1.6.3: @@ -3630,32 +3487,32 @@ packages: nofilter: 1.0.4 dev: true - /cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} + /cbor@9.0.1: + resolution: {integrity: sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==} + engines: {node: '>=16'} dependencies: nofilter: 3.1.0 dev: true - /chai-bn@0.2.2(bn.js@4.12.0)(chai@4.3.8): + /chai-bn@0.2.2(bn.js@4.12.0)(chai@4.3.10): resolution: {integrity: sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==} peerDependencies: bn.js: ^4.11.0 chai: ^4.0.0 dependencies: bn.js: 4.12.0 - chai: 4.3.8 + chai: 4.3.10 dev: true - /chai@4.3.8: - resolution: {integrity: sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==} + /chai@4.3.10: + resolution: {integrity: sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==} engines: {node: '>=4'} dependencies: assertion-error: 1.1.0 - check-error: 1.0.2 + check-error: 1.0.3 deep-eql: 4.1.3 - get-func-name: 2.0.0 - loupe: 2.3.4 + get-func-name: 2.0.2 + loupe: 2.3.7 pathval: 1.1.1 type-detect: 4.0.8 @@ -3714,8 +3571,10 @@ packages: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: true - /check-error@1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 /checkpoint-store@1.1.0: resolution: {integrity: sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg==} @@ -3779,6 +3638,7 @@ packages: /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + requiresBuild: true dev: true /ci-info@2.0.0: @@ -3789,6 +3649,7 @@ packages: resolution: {integrity: sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==} engines: {node: '>=4.0.0', npm: '>=3.0.0'} deprecated: This module has been superseded by the multiformats module + requiresBuild: true dependencies: buffer: 5.7.1 class-is: 1.1.0 @@ -3806,6 +3667,7 @@ packages: /class-is@1.1.0: resolution: {integrity: sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==} + requiresBuild: true dev: true /class-utils@0.3.6: @@ -3982,8 +3844,8 @@ packages: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} dev: true - /compare-versions@5.0.3: - resolution: {integrity: sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==} + /compare-versions@6.1.0: + resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} dev: true /component-emitter@1.3.0: @@ -4014,6 +3876,7 @@ packages: /content-disposition@0.5.3: resolution: {integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==} engines: {node: '>= 0.6'} + requiresBuild: true dependencies: safe-buffer: 5.1.2 dev: true @@ -4029,21 +3892,22 @@ packages: /content-type@1.0.4: resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true - /convert-source-map@1.8.0: - resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 + /convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + requiresBuild: true dev: true /cookie@0.4.0: resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /cookie@0.4.2: @@ -4088,6 +3952,7 @@ packages: /cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} + requiresBuild: true dependencies: object-assign: 4.1.1 vary: 1.1.2 @@ -4111,6 +3976,7 @@ packages: /create-ecdh@4.0.3: resolution: {integrity: sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==} + requiresBuild: true dependencies: bn.js: 4.12.0 elliptic: 6.5.4 @@ -4309,6 +4175,7 @@ packages: /decompress-response@3.3.0: resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} engines: {node: '>=4'} + requiresBuild: true dependencies: mimic-response: 1.0.1 dev: true @@ -4395,6 +4262,15 @@ packages: inherits: 2.0.4 dev: true + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + gopd: 1.0.1 + has-property-descriptors: 1.0.0 + dev: true + /define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} @@ -4408,6 +4284,15 @@ packages: object-keys: 1.1.1 dev: true + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + /define-property@0.2.5: resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} engines: {node: '>=0.10.0'} @@ -4430,8 +4315,8 @@ packages: isobject: 3.0.1 dev: true - /defined@1.0.0: - resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} + /defined@1.0.1: + resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} dev: true /delayed-stream@1.0.0: @@ -4442,6 +4327,7 @@ packages: /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /depd@2.0.0: @@ -4451,6 +4337,7 @@ packages: /des.js@1.0.1: resolution: {integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==} + requiresBuild: true dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 @@ -4458,6 +4345,7 @@ packages: /destroy@1.0.4: resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} + requiresBuild: true dev: true /detect-indent@4.0.0: @@ -4500,6 +4388,7 @@ packages: /diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + requiresBuild: true dependencies: bn.js: 4.12.0 miller-rabin: 4.0.1 @@ -4570,17 +4459,9 @@ packages: minimatch: 3.1.2 dev: true - /drbg.js@1.0.1: - resolution: {integrity: sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g==} - engines: {node: '>=0.10'} - dependencies: - browserify-aes: 1.2.0 - create-hash: 1.2.0 - create-hmac: 1.1.7 - dev: true - /duplexer3@0.1.4: resolution: {integrity: sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==} + requiresBuild: true dev: true /ecc-jsbn@0.1.2: @@ -4592,10 +4473,11 @@ packages: /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + requiresBuild: true dev: true - /electron-to-chromium@1.4.270: - resolution: {integrity: sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==} + /electron-to-chromium@1.4.556: + resolution: {integrity: sha512-6RPN0hHfzDU8D56E72YkDvnLw5Cj2NMXZGg3UkgyoHxjVhG99KZpsKgBWMmTy0Ei89xwan+rbRsVB9yzATmYzQ==} dev: true /elliptic@6.5.4: @@ -4620,6 +4502,7 @@ packages: /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + requiresBuild: true dev: true /encoding-down@5.0.4: @@ -4705,10 +4588,70 @@ packages: unbox-primitive: 1.0.2 dev: true + /es-abstract@1.22.2: + resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.1 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.0 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.0.1 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.11 + dev: true + /es-array-method-boxes-properly@1.0.0: resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} dev: true + /es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + has-tostringtag: 1.0.0 + dev: true + + /es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + dependencies: + has: 1.0.3 + dev: true + /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} @@ -4754,6 +4697,7 @@ packages: /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + requiresBuild: true dev: true /escape-string-regexp@1.0.5: @@ -4779,17 +4723,17 @@ packages: source-map: 0.2.0 dev: true - /eslint-config-prettier@9.0.0(eslint@8.49.0): + /eslint-config-prettier@9.0.0(eslint@8.51.0): resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.49.0 + eslint: 8.51.0 dev: true - /eslint-plugin-prettier@5.0.0(eslint-config-prettier@9.0.0)(eslint@8.49.0)(prettier@3.0.3): - resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.51.0)(prettier@3.0.3): + resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -4802,8 +4746,8 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.49.0 - eslint-config-prettier: 9.0.0(eslint@8.49.0) + eslint: 8.51.0 + eslint-config-prettier: 9.0.0(eslint@8.51.0) prettier: 3.0.3 prettier-linter-helpers: 1.0.0 synckit: 0.8.5 @@ -4822,15 +4766,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.49.0: - resolution: {integrity: sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==} + /eslint@8.51.0: + resolution: {integrity: sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) '@eslint-community/regexpp': 4.8.0 '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.49.0 + '@eslint/js': 8.51.0 '@humanwhocodes/config-array': 0.11.11 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -4921,6 +4865,7 @@ packages: /etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /eth-block-tracker@3.0.1: @@ -4932,7 +4877,7 @@ packages: ethjs-util: 0.1.6 json-rpc-engine: 3.8.0 pify: 2.3.0 - tape: 4.16.1 + tape: 4.17.0 transitivePeerDependencies: - supports-color dev: true @@ -4971,6 +4916,7 @@ packages: /eth-json-rpc-infura@3.2.1: resolution: {integrity: sha512-W7zR4DZvyTn23Bxc0EWsq4XGDdD63+XPUCEhV2zQvQGavDVC4ZpFDK4k99qN7bd7/fjj37+rxmuBOBeIqCA5Mw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. dependencies: cross-fetch: 2.2.6 eth-json-rpc-middleware: 1.6.0 @@ -4994,15 +4940,16 @@ packages: fetch-ponyfill: 4.1.0 json-rpc-engine: 3.8.0 json-rpc-error: 2.0.0 - json-stable-stringify: 1.0.1 + json-stable-stringify: 1.0.2 promise-to-callback: 1.0.0 - tape: 4.16.1 + tape: 4.17.0 transitivePeerDependencies: - supports-color dev: true /eth-lib@0.1.29: resolution: {integrity: sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==} + requiresBuild: true dependencies: bn.js: 4.12.0 elliptic: 6.5.4 @@ -5119,8 +5066,8 @@ packages: '@scure/bip39': 1.1.0 dev: true - /ethereum-waffle@3.3.0(typescript@5.2.2): - resolution: {integrity: sha512-4xm3RWAPCu5LlaVxYEg0tG3L7g5ovBw1GY/UebrzZ+OTx22vcPjI+bvelFlGBpkdnO5yOIFXjH2eK59tNAe9IA==} + /ethereum-waffle@3.4.4(typescript@5.2.2): + resolution: {integrity: sha512-PA9+jCjw4WC3Oc5ocSMBj5sXvueWQeAbvCA+hUlb6oFgwwKyq5ka3bWQ7QZcjzIX+TdFkxP4IbFmoY2D8Dkj9Q==} engines: {node: '>=10.0'} hasBin: true dependencies: @@ -5128,7 +5075,7 @@ packages: '@ethereum-waffle/compiler': 3.4.4(typescript@5.2.2) '@ethereum-waffle/mock-contract': 3.4.4 '@ethereum-waffle/provider': 3.4.4 - ethers: 5.6.1 + ethers: 5.7.2 transitivePeerDependencies: - bufferutil - encoding @@ -5141,7 +5088,7 @@ packages: resolution: {integrity: sha512-rCjJZ/AE96c/AAZc6O3kaog4FhOsAViaysBxqJNy2+LHP0ttH0zkZ7nXdVHOAyt6lFwLO0nlCwWszysG/ao1+g==} dependencies: bn.js: 4.12.0 - ethereumjs-util: 4.5.0 + ethereumjs-util: 4.5.1 dev: true /ethereumjs-abi@0.6.8: @@ -5227,14 +5174,14 @@ packages: ethereumjs-util: 6.2.1 dev: true - /ethereumjs-util@4.5.0: - resolution: {integrity: sha512-gT1zBY8aQKkexYu7XNeBZBnJsRLo+sWD1XWRLJOaDSz49/9kCOs6ERP52Bw/TA4uaVFKpM+O8ebWy44Ib5B6xw==} + /ethereumjs-util@4.5.1: + resolution: {integrity: sha512-WrckOZ7uBnei4+AKimpuF1B3Fv25OmoRgmYCpGsP7u8PFxXAmAgiJSYT2kRWnt6fVIlKaQlZvuwXp7PIrmn3/w==} dependencies: bn.js: 4.12.0 create-hash: 1.2.0 - keccakjs: 0.2.3 + elliptic: 6.5.4 + ethereum-cryptography: 0.1.3 rlp: 2.2.7 - secp256k1: 3.7.1 dev: true /ethereumjs-util@5.2.1: @@ -5307,7 +5254,7 @@ packages: merkle-patricia-tree: 2.3.2 rustbn.js: 0.2.0 safe-buffer: 5.2.1 - util.promisify: 1.1.1 + util.promisify: 1.1.2 dev: true /ethereumjs-wallet@0.6.5: @@ -5340,43 +5287,6 @@ packages: xmlhttprequest: 1.8.0 dev: true - /ethers@5.6.1: - resolution: {integrity: sha512-qtl/2W+dwmUa5Z3JqwsbV3JEBZZHNARe5K/A2ePcNAuhJYnEKIgGOT/O9ouPwBijSqVoQnmQMzi5D48LFNOY2A==} - dependencies: - '@ethersproject/abi': 5.6.0 - '@ethersproject/abstract-provider': 5.6.0 - '@ethersproject/abstract-signer': 5.6.0 - '@ethersproject/address': 5.6.0 - '@ethersproject/base64': 5.6.0 - '@ethersproject/basex': 5.6.0 - '@ethersproject/bignumber': 5.6.0 - '@ethersproject/bytes': 5.6.0 - '@ethersproject/constants': 5.6.0 - '@ethersproject/contracts': 5.6.0 - '@ethersproject/hash': 5.6.0 - '@ethersproject/hdnode': 5.6.0 - '@ethersproject/json-wallets': 5.6.0 - '@ethersproject/keccak256': 5.6.0 - '@ethersproject/logger': 5.0.6 - '@ethersproject/networks': 5.6.0 - '@ethersproject/pbkdf2': 5.6.0 - '@ethersproject/properties': 5.6.0 - '@ethersproject/providers': 5.6.1 - '@ethersproject/random': 5.6.0 - '@ethersproject/rlp': 5.6.0 - '@ethersproject/sha2': 5.6.0 - '@ethersproject/signing-key': 5.6.0 - '@ethersproject/solidity': 5.6.0 - '@ethersproject/strings': 5.6.0 - '@ethersproject/transactions': 5.6.0 - '@ethersproject/units': 5.6.0 - '@ethersproject/wallet': 5.6.0 - '@ethersproject/web': 5.6.0 - '@ethersproject/wordlists': 5.6.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - /ethers@5.7.2: resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} dependencies: @@ -5413,7 +5323,6 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true /ethjs-abi@0.2.1: resolution: {integrity: sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==} @@ -5451,6 +5360,7 @@ packages: /evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + requiresBuild: true dependencies: md5.js: 1.3.5 safe-buffer: 5.2.1 @@ -5504,6 +5414,7 @@ packages: /express@4.17.1: resolution: {integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==} engines: {node: '>= 0.10.0'} + requiresBuild: true dependencies: accepts: 1.3.7 array-flatten: 1.1.1 @@ -5596,6 +5507,10 @@ packages: checkpoint-store: 1.1.0 dev: true + /fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + dev: true + /fast-check@3.1.1: resolution: {integrity: sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==} engines: {node: '>=8.0.0'} @@ -5611,17 +5526,6 @@ packages: resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} dev: true - /fast-glob@3.2.12: - resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - /fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} @@ -5660,10 +5564,6 @@ packages: flat-cache: 3.0.4 dev: true - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: true - /fill-range@4.0.0: resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} engines: {node: '>=0.10.0'} @@ -5684,6 +5584,7 @@ packages: /finalhandler@1.1.2: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} + requiresBuild: true dependencies: debug: 2.6.9 encodeurl: 1.0.2 @@ -5815,10 +5716,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /foreach@2.0.5: - resolution: {integrity: sha512-ZBbtRiapkZYLsqoPyZOR+uPfto0GRMNQN1GwzZtZt7iZvPPbDDQV0JF5Hx4o/QFQ5c0vyuoZ98T8RSBbopzWtA==} - dev: true - /forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} dev: true @@ -5845,9 +5742,19 @@ packages: mime-types: 2.1.27 dev: true + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.27 + dev: true + /forwarded@0.1.2: resolution: {integrity: sha512-Ua9xNhH0b8pwE3yRbFfXJvfdWF0UHNCdeyb2sbi9Ul/M+r3PTdrz7Cv4SCfZRMjmzEM9PhraqfZFbGTIg3OMyA==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /fp-ts@1.19.3: @@ -5864,6 +5771,7 @@ packages: /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /fs-extra@0.30.0: @@ -5914,6 +5822,7 @@ packages: /fs-minipass@1.2.7: resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} + requiresBuild: true dependencies: minipass: 2.9.0 dev: true @@ -5957,6 +5866,16 @@ packages: functions-have-names: 1.2.3 dev: true + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + functions-have-names: 1.2.3 + dev: true + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true @@ -6018,8 +5937,8 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-func-name@2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} /get-intrinsic@1.1.3: resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} @@ -6029,6 +5948,15 @@ packages: has-symbols: 1.0.3 dev: true + /get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-proto: 1.0.1 + has-symbols: 1.0.3 + dev: true + /get-port@3.2.0: resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} engines: {node: '>=4'} @@ -6037,6 +5965,7 @@ packages: /get-stream@3.0.0: resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} engines: {node: '>=4'} + requiresBuild: true dev: true /get-stream@4.1.0: @@ -6200,6 +6129,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + /globby@10.0.2: resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} engines: {node: '>=8'} @@ -6207,7 +6143,7 @@ packages: '@types/glob': 7.1.1 array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.12 + fast-glob: 3.3.1 glob: 7.2.3 ignore: 5.2.4 merge2: 1.4.1 @@ -6226,6 +6162,12 @@ packages: slash: 3.0.0 dev: true + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.1 + dev: true + /got@12.1.0: resolution: {integrity: sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==} engines: {node: '>=14.16'} @@ -6248,6 +6190,7 @@ packages: /got@7.1.0: resolution: {integrity: sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==} engines: {node: '>=4'} + requiresBuild: true dependencies: '@types/keyv': 3.1.4 '@types/responselike': 1.0.0 @@ -6330,33 +6273,33 @@ packages: har-schema: 2.0.0 dev: true - /hardhat-abi-exporter@2.2.1(hardhat@2.17.3): + /hardhat-abi-exporter@2.2.1(hardhat@2.18.1): resolution: {integrity: sha512-Um7+RPvJEj+OqWjPoPKlTTkO1Akr10pqpgMk8Pw2jz2wrGv5XQBGNW5aQgGVDUosYktUIWDaEhcwwFKbFsir9A==} engines: {node: '>=12.10.0'} peerDependencies: hardhat: ^2.0.0 dependencies: - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /hardhat-contract-sizer@2.5.1(hardhat@2.17.3): + /hardhat-contract-sizer@2.5.1(hardhat@2.18.1): resolution: {integrity: sha512-28yRb73e30aBVaZOOHTlHZFIdIasA/iFunIehrUviIJTubvdQjtSiQUo2wexHFtt71mQeMPP8qjw2sdbgatDnQ==} peerDependencies: hardhat: ^2.0.0 dependencies: chalk: 4.1.2 cli-table3: 0.6.3 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) dev: true - /hardhat-gas-reporter@1.0.9(hardhat@2.17.3): + /hardhat-gas-reporter@1.0.9(hardhat@2.18.1): resolution: {integrity: sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==} peerDependencies: hardhat: ^2.0.2 dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.25 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -6370,8 +6313,8 @@ packages: solidity-comments: 0.0.2 dev: true - /hardhat@2.17.3(ts-node@10.9.1)(typescript@5.2.2): - resolution: {integrity: sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA==} + /hardhat@2.18.1(ts-node@10.9.1)(typescript@5.2.2): + resolution: {integrity: sha512-b55rW7Ka+fvJeg6oWuBTXoYQEUurevCCankjGNTwczwD3GnkhV9GEei7KUT+9IKmWx3lC+zyxlFxeDbg0gUoHw==} hasBin: true peerDependencies: ts-node: '*' @@ -6426,7 +6369,7 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.1(@types/node@16.18.52)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@16.18.58)(typescript@5.2.2) tsort: 0.0.1 typescript: 5.2.2 undici: 5.19.1 @@ -6470,8 +6413,14 @@ packages: get-intrinsic: 1.1.3 dev: true + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + /has-symbol-support-x@1.4.2: resolution: {integrity: sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==} + requiresBuild: true dev: true /has-symbols@1.0.3: @@ -6481,6 +6430,7 @@ packages: /has-to-string-tag-x@1.4.1: resolution: {integrity: sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==} + requiresBuild: true dependencies: has-symbol-support-x: 1.4.2 dev: true @@ -6621,6 +6571,7 @@ packages: /http-errors@1.7.2: resolution: {integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==} engines: {node: '>= 0.6'} + requiresBuild: true dependencies: depd: 1.1.2 inherits: 2.0.3 @@ -6632,6 +6583,7 @@ packages: /http-errors@1.7.3: resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} engines: {node: '>= 0.6'} + requiresBuild: true dependencies: depd: 1.1.2 inherits: 2.0.4 @@ -6767,6 +6719,7 @@ packages: /inherits@2.0.3: resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + requiresBuild: true dev: true /inherits@2.0.4: @@ -6776,11 +6729,20 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true - /internal-slot@1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + /internal-slot@1.0.3: + resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.1.3 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + + /internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.1 has: 1.0.3 side-channel: 1.0.4 dev: true @@ -6810,6 +6772,7 @@ packages: /ipaddr.js@1.9.0: resolution: {integrity: sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==} engines: {node: '>= 0.10'} + requiresBuild: true dev: true /is-accessor-descriptor@0.1.6: @@ -6831,6 +6794,14 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -6883,6 +6854,12 @@ packages: has: 1.0.3 dev: true + /is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + dependencies: + has: 1.0.3 + dev: true + /is-data-descriptor@0.1.4: resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} engines: {node: '>=0.10.0'} @@ -7037,6 +7014,7 @@ packages: /is-object@1.0.1: resolution: {integrity: sha512-+XzmTRB/JXoIdK20Ge8K8PRsP5UlthLaVhIRxzIwQ73jRgER8iRw98DilvERx/tSjOHLy9JM4sKUfLRMB5ui0Q==} + requiresBuild: true dev: true /is-path-inside@3.0.3: @@ -7047,6 +7025,7 @@ packages: /is-plain-obj@1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /is-plain-obj@2.1.0: @@ -7072,6 +7051,7 @@ packages: /is-retry-allowed@1.2.0: resolution: {integrity: sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /is-shared-array-buffer@1.0.2: @@ -7109,15 +7089,11 @@ packages: has-symbols: 1.0.3 dev: true - /is-typed-array@1.1.5: - resolution: {integrity: sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==} + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.2 - call-bind: 1.0.2 - es-abstract: 1.20.3 - foreach: 2.0.5 - has-symbols: 1.0.3 + which-typed-array: 1.1.11 dev: true /is-typedarray@1.0.0: @@ -7169,6 +7145,10 @@ packages: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: true + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true @@ -7185,6 +7165,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + /isomorphic-unfetch@3.1.0: + resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + dependencies: + node-fetch: 2.6.7 + unfetch: 4.2.0 + transitivePeerDependencies: + - encoding + dev: true + /isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} dev: true @@ -7216,11 +7205,16 @@ packages: /isurl@1.0.0: resolution: {integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==} engines: {node: '>= 4'} + requiresBuild: true dependencies: has-to-string-tag-x: 1.4.1 is-object: 1.0.1 dev: true + /js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + dev: true + /js-sdsl@4.4.2: resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} dev: true @@ -7233,10 +7227,6 @@ packages: resolution: {integrity: sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==} dev: true - /js-sha3@0.6.1: - resolution: {integrity: sha512-2OHj7sAZ9gnJS4lQsgIsTslmqVrNQdDC99bvwYGQKU1w6k/gwsTLeGBfWt8yHCuTOGqk7DXzuVlK8J+dDXnG7A==} - dev: true - /js-sha3@0.8.0: resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} @@ -7337,10 +7327,10 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json-stable-stringify@1.0.1: - resolution: {integrity: sha512-i/J297TW6xyj7sDFa7AmBPkQvLIxWr2kKPWI26tXydnZrzVAocNqn5DMNT1Mzk0vit1V5UkRM7C1KdVNp7Lmcg==} + /json-stable-stringify@1.0.2: + resolution: {integrity: sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==} dependencies: - jsonify: 0.0.0 + jsonify: 0.0.1 dev: true /json-stringify-safe@5.0.1: @@ -7380,8 +7370,8 @@ packages: graceful-fs: 4.2.10 dev: true - /jsonify@0.0.0: - resolution: {integrity: sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==} + /jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} dev: true /jsonpointer@5.0.1: @@ -7413,13 +7403,6 @@ packages: readable-stream: 3.6.0 dev: true - /keccakjs@0.2.3: - resolution: {integrity: sha512-BjLkNDcfaZ6l8HBG9tH0tpmDv3sS2mA7FNQxFHpCdzP3Gb2MVruXBSuoM66SnVxKJpAr5dKGdkHD+bDokt8fTg==} - dependencies: - browserify-sha3: 0.0.4 - sha3: 1.2.6 - dev: true - /keyv@3.1.0: resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==} requiresBuild: true @@ -7505,7 +7488,7 @@ packages: dependencies: inherits: 2.0.4 level-errors: 1.0.5 - readable-stream: 1.0.34 + readable-stream: 1.1.14 xtend: 4.0.2 dev: true @@ -7559,7 +7542,7 @@ packages: ltgt: 2.1.3 pull-defer: 0.2.3 pull-level: 2.0.4 - pull-stream: 3.6.14 + pull-stream: 3.7.0 typewiselite: 1.0.0 xtend: 4.0.2 dev: true @@ -7751,10 +7734,10 @@ packages: js-tokens: 4.0.0 dev: true - /loupe@2.3.4: - resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} dependencies: - get-func-name: 2.0.0 + get-func-name: 2.0.2 /lower-case-first@1.0.2: resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==} @@ -7769,6 +7752,7 @@ packages: /lowercase-keys@1.0.1: resolution: {integrity: sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /lowercase-keys@2.0.0: @@ -7848,6 +7832,7 @@ packages: /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /memdown@1.4.1: @@ -7889,6 +7874,7 @@ packages: /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} + requiresBuild: true dev: true /merge-stream@2.0.0: @@ -7928,6 +7914,7 @@ packages: /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /micromatch@3.1.10: @@ -7983,6 +7970,7 @@ packages: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true + requiresBuild: true dev: true /mimic-fn@2.1.0: @@ -7998,6 +7986,7 @@ packages: /mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} + requiresBuild: true dev: true /mimic-response@3.1.0: @@ -8047,8 +8036,13 @@ packages: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} dev: true + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + /minipass@2.9.0: resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} + requiresBuild: true dependencies: safe-buffer: 5.2.1 yallist: 3.1.1 @@ -8056,6 +8050,7 @@ packages: /minizlib@1.3.3: resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} + requiresBuild: true dependencies: minipass: 2.9.0 dev: true @@ -8072,6 +8067,7 @@ packages: resolution: {integrity: sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==} engines: {node: '>=4'} deprecated: This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that. + requiresBuild: true dependencies: mkdirp: 1.0.4 dev: true @@ -8130,37 +8126,6 @@ packages: yargs-unparser: 2.0.0 dev: true - /mocha@7.1.2: - resolution: {integrity: sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==} - engines: {node: '>= 8.10.0'} - hasBin: true - dependencies: - ansi-colors: 3.2.3 - browser-stdout: 1.3.1 - chokidar: 3.3.0 - debug: 3.2.6(supports-color@6.0.0) - diff: 3.5.0 - escape-string-regexp: 1.0.5 - find-up: 3.0.0 - glob: 7.1.3 - growl: 1.10.5 - he: 1.2.0 - js-yaml: 3.13.1 - log-symbols: 3.0.0 - minimatch: 3.0.4 - mkdirp: 0.5.5 - ms: 2.1.1 - node-environment-flags: 1.0.6 - object.assign: 4.1.0 - strip-json-comments: 2.0.1 - supports-color: 6.0.0 - which: 1.3.1 - wide-align: 1.1.3 - yargs: 13.3.2 - yargs-parser: 13.1.2 - yargs-unparser: 1.6.0 - dev: true - /mocha@7.2.0: resolution: {integrity: sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==} engines: {node: '>= 8.10.0'} @@ -8194,6 +8159,19 @@ packages: /mock-fs@4.12.0: resolution: {integrity: sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ==} + requiresBuild: true + dev: true + + /mock-property@1.0.2: + resolution: {integrity: sha512-GHVKHd3bFiXtvZtp23+8+EQLMeDJWcEVrSA2pOBs1KB5Uh2ww8Q+9fYDljS67k3GzU4DIDBa6+qRIgfZ2Bp+gQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + gopd: 1.0.1 + has: 1.0.3 + has-property-descriptors: 1.0.0 + isarray: 2.0.5 dev: true /module-error@1.0.2: @@ -8224,6 +8202,7 @@ packages: /multibase@0.6.1: resolution: {integrity: sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==} deprecated: This module has been superseded by the multiformats module + requiresBuild: true dependencies: base-x: 3.0.9 buffer: 5.7.1 @@ -8232,6 +8211,7 @@ packages: /multibase@0.7.0: resolution: {integrity: sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==} deprecated: This module has been superseded by the multiformats module + requiresBuild: true dependencies: base-x: 3.0.9 buffer: 5.7.1 @@ -8240,6 +8220,7 @@ packages: /multicodec@0.5.7: resolution: {integrity: sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==} deprecated: This module has been superseded by the multiformats module + requiresBuild: true dependencies: varint: 5.0.2 dev: true @@ -8247,6 +8228,7 @@ packages: /multicodec@1.0.4: resolution: {integrity: sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==} deprecated: This module has been superseded by the multiformats module + requiresBuild: true dependencies: buffer: 5.7.1 varint: 5.0.2 @@ -8254,26 +8236,20 @@ packages: /multihashes@0.4.21: resolution: {integrity: sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==} + requiresBuild: true dependencies: buffer: 5.7.1 multibase: 0.7.0 varint: 5.0.2 dev: true - /nan@2.13.2: - resolution: {integrity: sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==} - dev: true - - /nan@2.16.0: - resolution: {integrity: sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==} - dev: true - /nano-base32@1.0.1: resolution: {integrity: sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==} dev: true /nano-json-stream-parser@0.1.2: resolution: {integrity: sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==} + requiresBuild: true dev: true /nanoid@3.3.3: @@ -8312,6 +8288,7 @@ packages: /negotiator@0.6.2: resolution: {integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /neo-async@2.6.2: @@ -8483,6 +8460,14 @@ packages: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + + /object-inspect@1.13.0: + resolution: {integrity: sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==} + dev: true + /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} @@ -8537,6 +8522,17 @@ packages: es-abstract: 1.20.3 dev: true + /object.getownpropertydescriptors@2.1.7: + resolution: {integrity: sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==} + engines: {node: '>= 0.8'} + dependencies: + array.prototype.reduce: 1.0.6 + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + safe-array-concat: 1.0.1 + dev: true + /object.pick@1.3.0: resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} engines: {node: '>=0.10.0'} @@ -8549,7 +8545,7 @@ packages: dev: true /oboe@2.1.4: - resolution: {integrity: sha512-ymBJ4xSC6GBXLT9Y7lirj+xbqBLa+jADGJldGEYG7u8sZbS9GyG+u1Xk9c5cbriKwSpCg41qUhPjvU5xOpvIyQ==} + resolution: {integrity: sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=} requiresBuild: true dependencies: http-https: 1.0.0 @@ -8557,7 +8553,7 @@ packages: optional: true /oboe@2.1.5: - resolution: {integrity: sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==} + resolution: {integrity: sha1-VVQoTFQ6ImbXo48X4HOCH73jk80=} dependencies: http-https: 1.0.0 dev: true @@ -8565,6 +8561,7 @@ packages: /on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} + requiresBuild: true dependencies: ee-first: 1.1.1 dev: true @@ -8651,6 +8648,7 @@ packages: /p-cancelable@0.3.0: resolution: {integrity: sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==} engines: {node: '>=4'} + requiresBuild: true dev: true /p-cancelable@1.1.0: @@ -8667,6 +8665,7 @@ packages: /p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} + requiresBuild: true dev: true /p-limit@1.3.0: @@ -8728,6 +8727,7 @@ packages: /p-timeout@1.2.1: resolution: {integrity: sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA==} engines: {node: '>=4'} + requiresBuild: true dependencies: p-finally: 1.0.0 dev: true @@ -8757,6 +8757,7 @@ packages: /parse-asn1@5.1.5: resolution: {integrity: sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==} + requiresBuild: true dependencies: asn1.js: 4.10.1 browserify-aes: 1.2.0 @@ -8807,6 +8808,7 @@ packages: /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + requiresBuild: true dev: true /pascal-case@2.0.1: @@ -8842,16 +8844,16 @@ packages: - supports-color dev: true - /patch-package@6.4.7: - resolution: {integrity: sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==} - engines: {npm: '>5'} + /patch-package@6.5.1: + resolution: {integrity: sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==} + engines: {node: '>=10', npm: '>5'} hasBin: true dependencies: '@yarnpkg/lockfile': 1.1.0 - chalk: 2.4.2 + chalk: 4.1.2 cross-spawn: 6.0.5 find-yarn-workspace-root: 2.0.0 - fs-extra: 7.0.1 + fs-extra: 9.1.0 is-ci: 2.0.0 klaw-sync: 6.0.0 minimist: 1.2.6 @@ -8860,6 +8862,7 @@ packages: semver: 5.7.1 slash: 2.0.0 tmp: 0.0.33 + yaml: 1.10.2 dev: true /path-browserify@1.0.1: @@ -8915,6 +8918,7 @@ packages: /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + requiresBuild: true dev: true /path-type@1.1.0: @@ -9013,6 +9017,7 @@ packages: /prepend-http@1.0.4: resolution: {integrity: sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /prepend-http@2.0.0: @@ -9104,11 +9109,16 @@ packages: /proxy-addr@2.0.5: resolution: {integrity: sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==} engines: {node: '>= 0.10'} + requiresBuild: true dependencies: forwarded: 0.1.2 ipaddr.js: 1.9.0 dev: true + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true + /prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} dev: true @@ -9123,6 +9133,7 @@ packages: /public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + requiresBuild: true dependencies: bn.js: 4.12.0 browserify-rsa: 4.0.1 @@ -9147,7 +9158,7 @@ packages: pull-cat: 1.1.11 pull-live: 1.0.1 pull-pushable: 2.2.0 - pull-stream: 3.6.14 + pull-stream: 3.7.0 pull-window: 2.1.4 stream-to-pull-stream: 1.7.3 dev: true @@ -9156,15 +9167,15 @@ packages: resolution: {integrity: sha512-tkNz1QT5gId8aPhV5+dmwoIiA1nmfDOzJDlOOUpU5DNusj6neNd3EePybJ5+sITr2FwyCs/FVpx74YMCfc8YeA==} dependencies: pull-cat: 1.1.11 - pull-stream: 3.6.14 + pull-stream: 3.7.0 dev: true /pull-pushable@2.2.0: resolution: {integrity: sha512-M7dp95enQ2kaHvfCt2+DJfyzgCSpWVR2h2kWYnVsW6ZpxQBx5wOu0QWOvQPVoPnBLUZYitYP2y7HyHkLQNeGXg==} dev: true - /pull-stream@3.6.14: - resolution: {integrity: sha512-KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew==} + /pull-stream@3.7.0: + resolution: {integrity: sha512-Eco+/R004UaCK2qEDE8vGklcTG2OeZSVm1kTUQNrykEjDwcFXDZhygFDsW49DbXyJMEhHeRL3z5cRVqPAhXlIw==} dev: true /pull-window@2.1.4: @@ -9175,6 +9186,7 @@ packages: /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + requiresBuild: true dependencies: end-of-stream: 1.4.4 once: 1.4.0 @@ -9213,11 +9225,13 @@ packages: /qs@6.7.0: resolution: {integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==} engines: {node: '>=0.6'} + requiresBuild: true dev: true /query-string@5.1.1: resolution: {integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==} engines: {node: '>=0.10.0'} + requiresBuild: true dependencies: decode-uri-component: 0.2.0 object-assign: 4.1.1 @@ -9225,7 +9239,7 @@ packages: dev: true /querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + resolution: {integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=} engines: {node: '>=0.4.x'} deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: true @@ -9247,6 +9261,7 @@ packages: /randomfill@1.0.4: resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + requiresBuild: true dependencies: randombytes: 2.1.0 safe-buffer: 5.2.1 @@ -9255,11 +9270,13 @@ packages: /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /raw-body@2.4.0: resolution: {integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==} engines: {node: '>= 0.8'} + requiresBuild: true dependencies: bytes: 3.1.0 http-errors: 1.7.2 @@ -9303,6 +9320,15 @@ packages: string_decoder: 0.10.31 dev: true + /readable-stream@1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: true + /readable-stream@2.3.7: resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} dependencies: @@ -9342,7 +9368,7 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} dependencies: - resolve: 1.22.1 + resolve: 1.22.8 dev: true /recursive-readdir@2.2.2: @@ -9394,6 +9420,15 @@ packages: functions-have-names: 1.2.3 dev: true + /regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + set-function-name: 2.0.1 + dev: true + /regexpu-core@2.0.0: resolution: {integrity: sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ==} dependencies: @@ -9555,6 +9590,15 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /responselike@1.0.2: resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} requiresBuild: true @@ -9568,12 +9612,6 @@ packages: lowercase-keys: 2.0.0 dev: true - /resumer@0.0.0: - resolution: {integrity: sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w==} - dependencies: - through: 2.3.8 - dev: true - /ret@0.1.15: resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} engines: {node: '>=0.12'} @@ -9584,6 +9622,11 @@ packages: engines: {node: '>= 4'} dev: true + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: true + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -9643,6 +9686,16 @@ packages: resolution: {integrity: sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==} dev: true + /safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true @@ -9711,21 +9764,6 @@ packages: dev: true optional: true - /secp256k1@3.7.1: - resolution: {integrity: sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==} - engines: {node: '>=4.0.0'} - requiresBuild: true - dependencies: - bindings: 1.5.0 - bip66: 1.1.5 - bn.js: 4.12.0 - create-hash: 1.2.0 - drbg.js: 1.0.1 - elliptic: 6.5.4 - nan: 2.16.0 - safe-buffer: 5.2.1 - dev: true - /secp256k1@4.0.3: resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} engines: {node: '>=10.0.0'} @@ -9787,6 +9825,7 @@ packages: /send@0.17.1: resolution: {integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==} engines: {node: '>= 0.8.0'} + requiresBuild: true dependencies: debug: 2.6.9 depd: 1.1.2 @@ -9821,6 +9860,7 @@ packages: /serve-static@1.14.1: resolution: {integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==} engines: {node: '>= 0.8.0'} + requiresBuild: true dependencies: encodeurl: 1.0.2 escape-html: 1.0.3 @@ -9833,6 +9873,7 @@ packages: /servify@0.1.12: resolution: {integrity: sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==} engines: {node: '>=6'} + requiresBuild: true dependencies: body-parser: 1.19.0 cors: 2.8.5 @@ -9847,6 +9888,15 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true + /set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.0 + dev: true + /set-immediate-shim@1.0.1: resolution: {integrity: sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==} engines: {node: '>=0.10.0'} @@ -9872,6 +9922,7 @@ packages: /setprototypeof@1.1.1: resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} + requiresBuild: true dev: true /setprototypeof@1.2.0: @@ -9893,13 +9944,6 @@ packages: crypt: 0.0.2 dev: true - /sha3@1.2.6: - resolution: {integrity: sha512-KgLGmJGrmNB4JWVsAV11Yk6KbvsAiygWJc7t5IebWva/0NukNrjJqhtKhzy3Eiv2AKuGvhZZt7dt1mDo7HkoiQ==} - requiresBuild: true - dependencies: - nan: 2.13.2 - dev: true - /sha3@2.1.4: resolution: {integrity: sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==} dependencies: @@ -9958,10 +10002,12 @@ packages: /simple-concat@1.0.0: resolution: {integrity: sha512-pgxq9iGMSS24atefsqEznXW1Te610qB4pwMdrEg6mxczHh7sPtPyiixkP/VaQic8JjZofnIvT7CDeKlHqfbPBg==} + requiresBuild: true dev: true /simple-get@2.8.1: resolution: {integrity: sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==} + requiresBuild: true dependencies: decompress-response: 3.3.0 once: 1.4.0 @@ -10110,8 +10156,10 @@ packages: prettier: 2.8.8 dev: true - /solidity-ast@0.4.45: - resolution: {integrity: sha512-N6uqfaDulVZqjpjru+KvMLjV89M3hesyr/1/t8nkjohRagFSDmDxZvb9viKV98pdwpMzs61Nt2JAApgh0fkL0g==} + /solidity-ast@0.4.52: + resolution: {integrity: sha512-iOya9BSiB9jhM8Vf40n8lGELGzwrUc57rl5BhfNtJ5cvAaMvRcNlHeAMNvqJJyjoUnczqRbHqdivEqK89du3Cw==} + dependencies: + array.prototype.findlast: 1.2.3 dev: true /solidity-comments-darwin-arm64@0.0.2: @@ -10224,8 +10272,8 @@ packages: solidity-comments-win32-x64-msvc: 0.0.2 dev: true - /solidity-coverage@0.8.4(hardhat@2.17.3): - resolution: {integrity: sha512-xeHOfBOjdMF6hWTbt42iH4x+7j1Atmrf5OldDPMxI+i/COdExUxszOswD9qqvcBTaLGiOrrpnh9UZjSpt4rBsg==} + /solidity-coverage@0.8.5(hardhat@2.18.1): + resolution: {integrity: sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==} hasBin: true peerDependencies: hardhat: ^2.11.0 @@ -10240,15 +10288,15 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.17.3(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.18.1(ts-node@10.9.1)(typescript@5.2.2) jsonschema: 1.4.0 lodash: 4.17.21 - mocha: 7.1.2 + mocha: 10.2.0 node-emoji: 1.11.0 pify: 4.0.1 recursive-readdir: 2.2.2 sc-istanbul: 0.4.6 - semver: 7.5.0 + semver: 7.5.4 shelljs: 0.8.3 web3-utils: 1.8.0 transitivePeerDependencies: @@ -10383,6 +10431,7 @@ packages: /statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} + requiresBuild: true dev: true /statuses@2.0.1: @@ -10399,7 +10448,7 @@ packages: resolution: {integrity: sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==} dependencies: looper: 3.0.0 - pull-stream: 3.6.14 + pull-stream: 3.7.0 dev: true /streamsearch@1.1.0: @@ -10410,6 +10459,7 @@ packages: /strict-uri-encode@1.1.0: resolution: {integrity: sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /string-format@2.0.0: @@ -10451,13 +10501,13 @@ packages: strip-ansi: 6.0.1 dev: true - /string.prototype.trim@1.2.6: - resolution: {integrity: sha512-8lMR2m+U0VJTPp6JjvJTtGyc4FIGq9CdRt7O9p6T0e6K4vjU+OP+SQJpbe/SBmRcCUIvNUnjsbmY6lnMp8MhsQ==} + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 + define-properties: 1.2.1 + es-abstract: 1.22.2 dev: true /string.prototype.trimend@1.0.5: @@ -10468,6 +10518,14 @@ packages: es-abstract: 1.20.3 dev: true + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + dev: true + /string.prototype.trimstart@1.0.5: resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} dependencies: @@ -10476,6 +10534,14 @@ packages: es-abstract: 1.20.3 dev: true + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.1 + es-abstract: 1.22.2 + dev: true + /string_decoder@0.10.31: resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} dev: true @@ -10686,30 +10752,32 @@ packages: strip-ansi: 6.0.1 dev: true - /tape@4.16.1: - resolution: {integrity: sha512-U4DWOikL5gBYUrlzx+J0oaRedm2vKLFbtA/+BRAXboGWpXO7bMP8ddxlq3Cse2bvXFQ0jZMOj6kk3546mvCdFg==} + /tape@4.17.0: + resolution: {integrity: sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==} hasBin: true dependencies: + '@ljharb/resumer': 0.0.1 + '@ljharb/through': 2.3.11 call-bind: 1.0.2 deep-equal: 1.1.1 - defined: 1.0.0 + defined: 1.0.1 dotignore: 0.1.2 for-each: 0.3.3 glob: 7.2.3 has: 1.0.3 inherits: 2.0.4 is-regex: 1.1.4 - minimist: 1.2.6 - object-inspect: 1.12.2 - resolve: 1.22.1 - resumer: 0.0.0 - string.prototype.trim: 1.2.6 - through: 2.3.8 + minimist: 1.2.8 + mock-property: 1.0.2 + object-inspect: 1.12.3 + resolve: 1.22.8 + string.prototype.trim: 1.2.8 dev: true /tar@4.4.19: resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} engines: {node: '>=4.5'} + requiresBuild: true dependencies: chownr: 1.1.4 fs-minipass: 1.2.7 @@ -10761,13 +10829,10 @@ packages: xtend: 4.0.2 dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true - /timed-out@4.0.1: resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /title-case@2.1.1: @@ -10842,6 +10907,7 @@ packages: /toidentifier@1.0.0: resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} engines: {node: '>=0.6'} + requiresBuild: true dev: true /toidentifier@1.0.1: @@ -10920,7 +10986,7 @@ packages: ts-essentials: 1.0.4 dev: true - /ts-node@10.9.1(@types/node@16.18.52)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@16.18.58)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -10939,7 +11005,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 16.18.52 + '@types/node': 16.18.58 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -11017,6 +11083,7 @@ packages: /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + requiresBuild: true dependencies: media-typer: 0.3.0 mime-types: 2.1.27 @@ -11067,6 +11134,44 @@ packages: - supports-color dev: true + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: @@ -11121,6 +11226,7 @@ packages: /ultron@1.1.1: resolution: {integrity: sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==} + requiresBuild: true dev: true /unbox-primitive@1.0.2: @@ -11150,6 +11256,10 @@ packages: busboy: 1.6.0 dev: true + /unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + dev: true + /union-value@1.0.1: resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} engines: {node: '>=0.10.0'} @@ -11217,6 +11327,7 @@ packages: /url-parse-lax@1.0.0: resolution: {integrity: sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==} engines: {node: '>=0.10.0'} + requiresBuild: true dependencies: prepend-http: 1.0.4 dev: true @@ -11231,11 +11342,13 @@ packages: /url-set-query@1.0.0: resolution: {integrity: sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==} + requiresBuild: true dev: true /url-to-options@1.0.1: resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==} engines: {node: '>= 4'} + requiresBuild: true dev: true /url@0.11.0: @@ -11266,14 +11379,16 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - /util.promisify@1.1.1: - resolution: {integrity: sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==} + /util.promisify@1.1.2: + resolution: {integrity: sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA==} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.1 for-each: 0.3.3 + has-proto: 1.0.1 has-symbols: 1.0.3 - object.getownpropertydescriptors: 2.1.4 + object.getownpropertydescriptors: 2.1.7 + safe-array-concat: 1.0.1 dev: true /util@0.12.3: @@ -11282,14 +11397,15 @@ packages: inherits: 2.0.4 is-arguments: 1.0.4 is-generator-function: 1.0.8 - is-typed-array: 1.1.5 + is-typed-array: 1.1.12 safe-buffer: 5.2.1 - which-typed-array: 1.1.4 + which-typed-array: 1.1.11 dev: true /utils-merge@1.0.1: resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=} engines: {node: '>= 0.4.0'} + requiresBuild: true dev: true /uuid@2.0.1: @@ -11327,11 +11443,13 @@ packages: /varint@5.0.2: resolution: {integrity: sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==} + requiresBuild: true dev: true /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + requiresBuild: true dev: true /verror@1.10.0: @@ -11967,7 +12085,7 @@ packages: ethereumjs-util: 5.2.1 ethereumjs-vm: 2.6.0 json-rpc-error: 2.0.0 - json-stable-stringify: 1.0.1 + json-stable-stringify: 1.0.2 promise-to-callback: 1.0.0 readable-stream: 2.3.7 request: 2.88.2 @@ -12275,17 +12393,15 @@ packages: resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} dev: true - /which-typed-array@1.1.4: - resolution: {integrity: sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==} + /which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.2 + available-typed-arrays: 1.0.5 call-bind: 1.0.2 - es-abstract: 1.20.3 - foreach: 2.0.5 - function-bind: 1.1.1 - has-symbols: 1.0.3 - is-typed-array: 1.1.5 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 dev: true /which@1.3.1: @@ -12368,6 +12484,7 @@ packages: /ws@3.3.3: resolution: {integrity: sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==} + requiresBuild: true peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -12423,12 +12540,14 @@ packages: /xhr-request-promise@0.1.2: resolution: {integrity: sha512-yAQlCCNLwPgoGxw4k+IdRp1uZ7MZibS4kFw2boSUOesjnmvcxxj73j5a8KavE5Bzas++8P49OpJ4m8qjWGiDsA==} + requiresBuild: true dependencies: xhr-request: 1.1.0 dev: true /xhr-request@1.1.0: resolution: {integrity: sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==} + requiresBuild: true dependencies: buffer-to-arraybuffer: 0.0.5 object-assign: 4.1.1 @@ -12497,6 +12616,11 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + /yargs-parser@13.1.2: resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} dependencies: @@ -12600,3 +12724,9 @@ packages: bn.js: 4.12.0 ethereumjs-util: 6.2.1 dev: true + + github.com/smartcontractkit/chainlink-solhint-rules/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2: + resolution: {tarball: https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/6229ce5d3cc3e4a2454411bebc887c5ca240dcf2} + name: '@chainlink/solhint-plugin-chainlink-solidity' + version: 1.0.1 + dev: true diff --git a/contracts/remappings.txt b/contracts/remappings.txt index cf7275c1b3b..f0ac4993c2c 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -1,6 +1,5 @@ ds-test/=foundry-lib/forge-std/lib/ds-test/src forge-std/=foundry-lib/forge-std/src -openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/ @openzeppelin/=node_modules/@openzeppelin/ hardhat/=node_modules/hardhat/ diff --git a/contracts/scripts/generate-automation-master-interface.ts b/contracts/scripts/generate-automation-master-interface.ts index 5b71c99bc75..de71c56806b 100644 --- a/contracts/scripts/generate-automation-master-interface.ts +++ b/contracts/scripts/generate-automation-master-interface.ts @@ -26,6 +26,14 @@ for (const abi of abis) { const id = utils.id(JSON.stringify(entry)) if (!abiSet.has(id)) { abiSet.add(id) + if ( + entry.type === 'function' && + (entry.name === 'checkUpkeep' || + entry.name === 'checkCallback' || + entry.name === 'simulatePerformUpkeep') + ) { + entry.stateMutability = 'view' // override stateMutability for check / callback / simulate functions + } combinedABI.push(entry) } } diff --git a/contracts/scripts/native_solc_compile_all b/contracts/scripts/native_solc_compile_all index e695c49206c..a2f2f1a0bc3 100755 --- a/contracts/scripts/native_solc_compile_all +++ b/contracts/scripts/native_solc_compile_all @@ -12,7 +12,7 @@ python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt # 6 and 7 are legacy contracts, for each other product we have a native_solc_compile_all_$product script # These scripts can be run individually, or all together with this script. # To add new CL products, simply write a native_solc_compile_all_$product script and add it to the list below. -for product in 6 7 feeds functions llo-feeds transmission vrf automation logpoller events_mock shared +for product in 6 7 feeds functions llo-feeds transmission vrf automation operatorforwarder logpoller events_mock shared do $SCRIPTPATH/native_solc_compile_all_$product done diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index 005570f4c12..414453c8482 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -39,9 +39,6 @@ compileContract automation/UpkeepTranscoder.sol compileContract automation/mocks/MockAggregatorProxy.sol compileContract automation/testhelpers/LogUpkeepCounter.sol -# Keepers x VRF v2 -compileContract KeepersVRFConsumer.sol - compileContract automation/mocks/KeeperRegistrar1_2Mock.sol compileContract automation/mocks/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.sol @@ -62,6 +59,15 @@ compileContract automation/v2_1/AutomationUtils2_1.sol compileContract automation/v2_1/AutomationForwarderLogic.sol compileContract automation/testhelpers/LogTriggeredStreamsLookup.sol compileContract automation/testhelpers/DummyProtocol.sol + +compileContract automation/testhelpers/KeeperBase.sol +compileContract automation/testhelpers/KeeperCompatibleInterface.sol +compileContract automation/testhelpers/KeeperConsumer.sol +compileContract automation/testhelpers/KeeperConsumerPerformance.sol +compileContract automation/testhelpers/PerformDataChecker.sol +compileContract automation/testhelpers/UpkeepPerformCounterRestrictive.sol +compileContract automation/testhelpers/UpkeepCounter.sol + compileContract automation/interfaces/StreamsLookupCompatibleInterface.sol compileContract tests/VerifiableLoadUpkeep.sol diff --git a/contracts/scripts/native_solc_compile_all_feeds b/contracts/scripts/native_solc_compile_all_feeds index e37ca833ac6..2bbd9fe869c 100755 --- a/contracts/scripts/native_solc_compile_all_feeds +++ b/contracts/scripts/native_solc_compile_all_feeds @@ -30,6 +30,3 @@ compileContract () { compileContract interfaces/AggregatorV2V3Interface.sol compileContract Chainlink.sol compileContract ChainlinkClient.sol - -# Feeds -compileContract dev/DerivedPriceFeed.sol \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_functions b/contracts/scripts/native_solc_compile_all_functions index 99ded8afbb8..26e4c0c6e50 100755 --- a/contracts/scripts/native_solc_compile_all_functions +++ b/contracts/scripts/native_solc_compile_all_functions @@ -6,41 +6,22 @@ echo " ┌─────────────────────── echo " │ Compiling Functions contracts... │" echo " └──────────────────────────────────────────────┘" -SOLC_VERSION="0.8.6" OPTIMIZE_RUNS=1000000 SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" +ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../ && pwd -P )" python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt -solc-select install $SOLC_VERSION -solc-select use $SOLC_VERSION -export SOLC_VERSION=$SOLC_VERSION - - compileContract () { - solc --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ - -o $ROOT/contracts/solc/v$SOLC_VERSION/functions/$1 \ + solc @openzeppelin/=$ROOT/node_modules/@openzeppelin/ \ + --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ + -o $ROOT/solc/v$SOLC_VERSION/functions/$1 \ --abi --bin \ - --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/src/v0.8/functions \ - $ROOT/contracts/src/v0.8/functions/$2 + --allow-paths $ROOT/src/v0.8,$ROOT/node_modules \ + $ROOT/src/v0.8/functions/$2 } -########################## -# Version 0 (Testnet Beta) -########################## - -compileContract v0_0_0 dev/v0_0_0/Functions.sol -compileContract v0_0_0 dev/v0_0_0/FunctionsBillingRegistry.sol -compileContract v0_0_0 dev/v0_0_0/FunctionsClient.sol -compileContract v0_0_0 dev/v0_0_0/FunctionsOracle.sol -compileContract v0_0_0 dev/v0_0_0/example/FunctionsClientExample.sol - -# Test helpers -compileContract v0_0_0 tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol -compileContract v0_0_0 tests/v0_0_0/testhelpers/FunctionsOracleWithInit.sol - ############################ # Version 1 (Mainnet Preview) ############################ @@ -50,15 +31,15 @@ solc-select install $SOLC_VERSION solc-select use $SOLC_VERSION export SOLC_VERSION=$SOLC_VERSION -compileContract v1_0_0 dev/v1_0_0/libraries/FunctionsRequest.sol -compileContract v1_0_0 dev/v1_0_0/FunctionsRouter.sol -compileContract v1_0_0 dev/v1_0_0/FunctionsCoordinator.sol -compileContract v1_0_0 dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol -compileContract v1_0_0 dev/v1_0_0/example/FunctionsClientExample.sol +compileContract v1_X dev/v1_X/libraries/FunctionsRequest.sol +compileContract v1_X dev/v1_X/FunctionsRouter.sol +compileContract v1_X dev/v1_X/FunctionsCoordinator.sol +compileContract v1_X dev/v1_X/accessControl/TermsOfServiceAllowList.sol +compileContract v1_X dev/v1_X/example/FunctionsClientExample.sol # Test helpers -compileContract v1_0_0 tests/v1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol -compileContract v1_0_0 tests/v1_0_0/testhelpers/FunctionsLoadTestClient.sol +compileContract v1_X tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol +compileContract v1_X tests/v1_X/testhelpers/FunctionsLoadTestClient.sol # Mocks -compileContract v1_0_0 dev/v1_0_0/mocks/FunctionsV1EventsMock.sol +compileContract v1_X dev/v1_X/mocks/FunctionsV1EventsMock.sol diff --git a/contracts/scripts/native_solc_compile_all_operatorforwarder b/contracts/scripts/native_solc_compile_all_operatorforwarder new file mode 100755 index 00000000000..3bc5cb9249f --- /dev/null +++ b/contracts/scripts/native_solc_compile_all_operatorforwarder @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e + +echo " ┌──────────────────────────────────────────────┐" +echo " │ Compiling Operator Forwarder contracts... │" +echo " └──────────────────────────────────────────────┘" + +SOLC_VERSION="0.8.19" +OPTIMIZE_RUNS=1000000 + +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )" +python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt + +solc-select install $SOLC_VERSION +solc-select use $SOLC_VERSION +export SOLC_VERSION=$SOLC_VERSION + +compileContract () { + solc @openzeppelin/=$ROOT/contracts/node_modules/@openzeppelin/ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ + -o $ROOT/contracts/solc/v$SOLC_VERSION \ + --abi --bin --allow-paths $ROOT/contracts/src/v0.8,$ROOT/contracts/node_modules\ + $ROOT/contracts/src/v0.8/$1 +} + +# Contracts +compileContract operatorforwarder/dev/AuthorizedForwarder.sol +compileContract operatorforwarder/dev/AuthorizedReceiver.sol +compileContract operatorforwarder/dev/Operator.sol +compileContract operatorforwarder/dev/OperatorFactory.sol + diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index e7199f81feb..705cedce7ab 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -27,4 +27,5 @@ compileContract () { compileContract shared/token/ERC677/BurnMintERC677.sol compileContract shared/token/ERC677/LinkToken.sol +compileContract shared/mocks/WERC20Mock.sol compileContract vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/ERC20.sol diff --git a/contracts/scripts/native_solc_compile_all_transmission b/contracts/scripts/native_solc_compile_all_transmission index 6bd237f4a7d..e08f38e2bac 100755 --- a/contracts/scripts/native_solc_compile_all_transmission +++ b/contracts/scripts/native_solc_compile_all_transmission @@ -25,13 +25,13 @@ compileContract () { } # Contracts -compileContract dev/transmission/ERC-4337/SCA.sol -compileContract dev/transmission/ERC-4337/Paymaster.sol -compileContract dev/transmission/ERC-4337/SmartContractAccountFactory.sol +compileContract transmission/dev/ERC-4337/SCA.sol +compileContract transmission/dev/ERC-4337/Paymaster.sol +compileContract transmission/dev/ERC-4337/SmartContractAccountFactory.sol # Testhelpers -compileContract dev/transmission/testhelpers/SmartContractAccountHelper.sol -compileContract dev/transmission/testhelpers/Greeter.sol +compileContract transmission/dev/testhelpers/SmartContractAccountHelper.sol +compileContract transmission/dev/testhelpers/Greeter.sol # Vendor compileContract vendor/entrypoint/core/EntryPoint.sol diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 0a3b1367bdf..80adba8e6f7 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -36,10 +36,11 @@ compileContract vrf/VRFRequestIDBase.sol compileContract vrf/VRFConsumerBase.sol compileContract vrf/testhelpers/VRFConsumer.sol compileContract vrf/testhelpers/VRFRequestIDBaseTestHelper.sol -compileContract mocks/VRFCoordinatorMock.sol +compileContract vrf/mocks/VRFCoordinatorMock.sol # VRF V2 compileContract vrf/VRFConsumerBaseV2.sol +compileContract vrf/testhelpers/ChainSpecificUtilHelper.sol compileContract vrf/testhelpers/VRFConsumerV2.sol compileContract vrf/testhelpers/VRFMaliciousConsumerV2.sol compileContract vrf/testhelpers/VRFTestHelper.sol @@ -51,35 +52,38 @@ compileContract vrf/BatchBlockhashStore.sol compileContract vrf/BatchVRFCoordinatorV2.sol compileContract vrf/testhelpers/VRFCoordinatorV2TestHelper.sol compileContractAltOpts vrf/VRFCoordinatorV2.sol 10000 -compileContract mocks/VRFCoordinatorV2Mock.sol +compileContract vrf/mocks/VRFCoordinatorV2Mock.sol compileContract vrf/VRFOwner.sol +compileContract vrf/dev/VRFSubscriptionBalanceMonitor.sol +compileContract vrf/KeepersVRFConsumer.sol # VRF V2Plus -compileContract dev/interfaces/IVRFCoordinatorV2PlusInternal.sol -compileContract dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol -compileContractAltOpts dev/vrf/VRFCoordinatorV2_5.sol 500 -compileContract dev/vrf/BatchVRFCoordinatorV2Plus.sol -compileContract dev/vrf/VRFV2PlusWrapper.sol -compileContract dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol -compileContract dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol -compileContract dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol -compileContract dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol -compileContract dev/vrf/libraries/VRFV2PlusClient.sol -compileContract dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol -compileContract dev/vrf/TrustedBlockhashStore.sol -compileContract dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol -compileContractAltOpts dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 -compileContract dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +compileContract vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol +compileContract vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol +compileContractAltOpts vrf/dev/VRFCoordinatorV2_5.sol 50 +compileContract vrf/dev/BatchVRFCoordinatorV2Plus.sol +compileContract vrf/dev/VRFV2PlusWrapper.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol +compileContract vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol +compileContract vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +compileContract vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol +compileContract vrf/dev/libraries/VRFV2PlusClient.sol +compileContract vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +compileContract vrf/dev/TrustedBlockhashStore.sol +compileContract vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +compileContractAltOpts vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol 5 +compileContract vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol # VRF V2 Wrapper compileContract vrf/VRFV2Wrapper.sol -compileContract interfaces/VRFV2WrapperInterface.sol +compileContract vrf/interfaces/VRFV2WrapperInterface.sol compileContract vrf/VRFV2WrapperConsumerBase.sol compileContract vrf/testhelpers/VRFV2WrapperConsumerExample.sol +compileContract vrf/testhelpers/VRFv2Consumer.sol # VRF Consumers and Mocks compileContract vrf/testhelpers/VRFExternalSubOwnerExample.sol @@ -89,3 +93,8 @@ compileContract vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol compileContract vrf/testhelpers/VRFLoadTestExternalSubOwner.sol compileContract vrf/testhelpers/VRFV2LoadTestWithMetrics.sol compileContract vrf/testhelpers/VRFV2OwnerTestConsumer.sol + +# Helper contracts +compileContract vrf/interfaces/IAuthorizedReceiver.sol +compileContract vrf/interfaces/VRFCoordinatorV2Interface.sol +compileContract vrf/interfaces/VRFV2WrapperInterface.sol diff --git a/contracts/src/v0.8/ChainSpecificUtil.sol b/contracts/src/v0.8/ChainSpecificUtil.sol index 324121c9fa5..172d8c526f2 100644 --- a/contracts/src/v0.8/ChainSpecificUtil.sol +++ b/contracts/src/v0.8/ChainSpecificUtil.sol @@ -3,27 +3,60 @@ pragma solidity ^0.8.4; import {ArbSys} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; import {ArbGasInfo} from "./vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "./vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; -//@dev A library that abstracts out opcodes that behave differently across chains. -//@dev The methods below return values that are pertinent to the given chain. -//@dev For instance, ChainSpecificUtil.getBlockNumber() returns L2 block number in L2 chains +/// @dev A library that abstracts out opcodes that behave differently across chains. +/// @dev The methods below return values that are pertinent to the given chain. +/// @dev For instance, ChainSpecificUtil.getBlockNumber() returns L2 block number in L2 chains library ChainSpecificUtil { + // ------------ Start Arbitrum Constants ------------ + + /// @dev ARBSYS_ADDR is the address of the ArbSys precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbSys.sol#L10 address private constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); ArbSys private constant ARBSYS = ArbSys(ARBSYS_ADDR); + + /// @dev ARBGAS_ADDR is the address of the ArbGasInfo precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbGasInfo.sol#L10 address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); + uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; - function getBlockhash(uint64 blockNumber) internal view returns (bytes32) { + // ------------ End Arbitrum Constants ------------ + + // ------------ Start Optimism Constants ------------ + /// @dev L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + /// @dev OVM_GASPRICEORACLE_ADDR is the address of the OVM_GasPriceOracle precompile on Optimism. + /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR); + + uint256 private constant OP_MAINNET_CHAIN_ID = 10; + uint256 private constant OP_GOERLI_CHAIN_ID = 420; + uint256 private constant OP_SEPOLIA_CHAIN_ID = 11155420; + + /// @dev Base is a OP stack based rollup and follows the same L1 pricing logic as Optimism. + uint256 private constant BASE_MAINNET_CHAIN_ID = 8453; + uint256 private constant BASE_GOERLI_CHAIN_ID = 84531; + + // ------------ End Optimism Constants ------------ + + /** + * @notice Returns the blockhash for the given blockNumber. + * @notice If the blockNumber is more than 256 blocks in the past, returns the empty string. + * @notice When on a known Arbitrum chain, it uses ArbSys.arbBlockHash to get the blockhash. + * @notice Otherwise, it uses the blockhash opcode. + * @notice Note that the blockhash opcode will return the L2 blockhash on Optimism. + */ + function _getBlockhash(uint64 blockNumber) internal view returns (bytes32) { uint256 chainid = block.chainid; - if ( - chainid == ARB_MAINNET_CHAIN_ID || - chainid == ARB_GOERLI_TESTNET_CHAIN_ID || - chainid == ARB_SEPOLIA_TESTNET_CHAIN_ID - ) { - if ((getBlockNumber() - blockNumber) > 256 || blockNumber >= getBlockNumber()) { + if (_isArbitrumChainId(chainid)) { + if ((_getBlockNumber() - blockNumber) > 256 || blockNumber >= _getBlockNumber()) { return ""; } return ARBSYS.arbBlockHash(blockNumber); @@ -31,18 +64,34 @@ library ChainSpecificUtil { return blockhash(blockNumber); } - function getBlockNumber() internal view returns (uint256) { + /** + * @notice Returns the block number of the current block. + * @notice When on a known Arbitrum chain, it uses ArbSys.arbBlockNumber to get the block number. + * @notice Otherwise, it uses the block.number opcode. + * @notice Note that the block.number opcode will return the L2 block number on Optimism. + */ + function _getBlockNumber() internal view returns (uint256) { uint256 chainid = block.chainid; - if (chainid == ARB_MAINNET_CHAIN_ID || chainid == ARB_GOERLI_TESTNET_CHAIN_ID) { + if (_isArbitrumChainId(chainid)) { return ARBSYS.arbBlockNumber(); } return block.number; } - function getCurrentTxL1GasFees() internal view returns (uint256) { + /** + * @notice Returns the L1 fees that will be paid for the current transaction, given any calldata + * @notice for the current transaction. + * @notice When on a known Arbitrum chain, it uses ArbGas.getCurrentTxL1GasFees to get the fees. + * @notice On Arbitrum, the provided calldata is not used to calculate the fees. + * @notice On Optimism, the provided calldata is passed to the OVM_GasPriceOracle predeploy + * @notice and getL1Fee is called to get the fees. + */ + function _getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256) { uint256 chainid = block.chainid; - if (chainid == ARB_MAINNET_CHAIN_ID || chainid == ARB_GOERLI_TESTNET_CHAIN_ID) { + if (_isArbitrumChainId(chainid)) { return ARBGAS.getCurrentTxL1GasFees(); + } else if (_isOptimismChainId(chainid)) { + return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, L1_FEE_DATA_PADDING)); } return 0; } @@ -51,14 +100,62 @@ library ChainSpecificUtil { * @notice Returns the gas cost in wei of calldataSizeBytes of calldata being posted * @notice to L1. */ - function getL1CalldataGasCost(uint256 calldataSizeBytes) internal view returns (uint256) { + function _getL1CalldataGasCost(uint256 calldataSizeBytes) internal view returns (uint256) { uint256 chainid = block.chainid; - if (chainid == ARB_MAINNET_CHAIN_ID || chainid == ARB_GOERLI_TESTNET_CHAIN_ID) { + if (_isArbitrumChainId(chainid)) { (, uint256 l1PricePerByte, , , , ) = ARBGAS.getPricesInWei(); // see https://developer.arbitrum.io/devs-how-tos/how-to-estimate-gas#where-do-we-get-all-this-information-from // for the justification behind the 140 number. return l1PricePerByte * (calldataSizeBytes + 140); + } else if (_isOptimismChainId(chainid)) { + return _calculateOptimismL1DataFee(calldataSizeBytes); } return 0; } + + /** + * @notice Return true if and only if the provided chain ID is an Arbitrum chain ID. + */ + function _isArbitrumChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == ARB_MAINNET_CHAIN_ID || + chainId == ARB_GOERLI_TESTNET_CHAIN_ID || + chainId == ARB_SEPOLIA_TESTNET_CHAIN_ID; + } + + /** + * @notice Return true if and only if the provided chain ID is an Optimism chain ID. + * @notice Note that optimism chain id's are also OP stack chain id's. + */ + function _isOptimismChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == OP_MAINNET_CHAIN_ID || + chainId == OP_GOERLI_CHAIN_ID || + chainId == OP_SEPOLIA_CHAIN_ID || + chainId == BASE_MAINNET_CHAIN_ID || + chainId == BASE_GOERLI_CHAIN_ID; + } + + function _calculateOptimismL1DataFee(uint256 calldataSizeBytes) internal view returns (uint256) { + // from: https://community.optimism.io/docs/developers/build/transaction-fees/#the-l1-data-fee + // l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead + // tx_data_gas = count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16 + // note we conservatively assume all non-zero bytes. + uint256 l1BaseFeeWei = OVM_GASPRICEORACLE.l1BaseFee(); + uint256 numZeroBytes = 0; + uint256 numNonzeroBytes = calldataSizeBytes - numZeroBytes; + uint256 txDataGas = numZeroBytes * 4 + numNonzeroBytes * 16; + uint256 fixedOverhead = OVM_GASPRICEORACLE.overhead(); + + // The scalar is some value like 0.684, but is represented as + // that times 10 ^ number of scalar decimals. + // e.g scalar = 0.684 * 10^6 + // The divisor is used to divide that and have a net result of the true scalar. + uint256 scalar = OVM_GASPRICEORACLE.scalar(); + uint256 scalarDecimals = OVM_GASPRICEORACLE.decimals(); + uint256 divisor = 10 ** scalarDecimals; + + uint256 l1DataFee = (l1BaseFeeWei * (txDataGas + fixedOverhead) * scalar) / divisor; + return l1DataFee; + } } diff --git a/contracts/src/v0.8/Chainlink.sol b/contracts/src/v0.8/Chainlink.sol index 0475a351473..e511cfc8085 100644 --- a/contracts/src/v0.8/Chainlink.sol +++ b/contracts/src/v0.8/Chainlink.sol @@ -9,7 +9,8 @@ import {BufferChainlink} from "./vendor/BufferChainlink.sol"; * @dev Uses imported CBOR library for encoding to buffer */ library Chainlink { - uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint256 internal constant defaultBufferSize = 256; using CBORChainlink for BufferChainlink.buffer; @@ -30,7 +31,7 @@ library Chainlink { * @param callbackFunc The callback function signature * @return The initialized request */ - function initialize( + function _initialize( Request memory self, bytes32 jobId, address callbackAddr, @@ -49,7 +50,7 @@ library Chainlink { * @param self The initialized request * @param data The CBOR data */ - function setBuffer(Request memory self, bytes memory data) internal pure { + function _setBuffer(Request memory self, bytes memory data) internal pure { BufferChainlink.init(self.buf, data.length); BufferChainlink.append(self.buf, data); } @@ -60,7 +61,7 @@ library Chainlink { * @param key The name of the key * @param value The string value to add */ - function add(Request memory self, string memory key, string memory value) internal pure { + function _add(Request memory self, string memory key, string memory value) internal pure { self.buf.encodeString(key); self.buf.encodeString(value); } @@ -71,7 +72,7 @@ library Chainlink { * @param key The name of the key * @param value The bytes value to add */ - function addBytes(Request memory self, string memory key, bytes memory value) internal pure { + function _addBytes(Request memory self, string memory key, bytes memory value) internal pure { self.buf.encodeString(key); self.buf.encodeBytes(value); } @@ -82,7 +83,7 @@ library Chainlink { * @param key The name of the key * @param value The int256 value to add */ - function addInt(Request memory self, string memory key, int256 value) internal pure { + function _addInt(Request memory self, string memory key, int256 value) internal pure { self.buf.encodeString(key); self.buf.encodeInt(value); } @@ -93,7 +94,7 @@ library Chainlink { * @param key The name of the key * @param value The uint256 value to add */ - function addUint(Request memory self, string memory key, uint256 value) internal pure { + function _addUint(Request memory self, string memory key, uint256 value) internal pure { self.buf.encodeString(key); self.buf.encodeUInt(value); } @@ -104,7 +105,7 @@ library Chainlink { * @param key The name of the key * @param values The array of string values to add */ - function addStringArray(Request memory self, string memory key, string[] memory values) internal pure { + function _addStringArray(Request memory self, string memory key, string[] memory values) internal pure { self.buf.encodeString(key); self.buf.startArray(); for (uint256 i = 0; i < values.length; i++) { diff --git a/contracts/src/v0.8/ChainlinkClient.sol b/contracts/src/v0.8/ChainlinkClient.sol index fda69143f45..2d9302faef7 100644 --- a/contracts/src/v0.8/ChainlinkClient.sol +++ b/contracts/src/v0.8/ChainlinkClient.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./Chainlink.sol"; -import "./interfaces/ENSInterface.sol"; -import "./shared/interfaces/LinkTokenInterface.sol"; -import "./interfaces/ChainlinkRequestInterface.sol"; -import "./interfaces/OperatorInterface.sol"; -import "./interfaces/PointerInterface.sol"; +import {Chainlink} from "./Chainlink.sol"; +import {ENSInterface} from "./interfaces/ENSInterface.sol"; +import {LinkTokenInterface} from "./shared/interfaces/LinkTokenInterface.sol"; +import {ChainlinkRequestInterface} from "./interfaces/ChainlinkRequestInterface.sol"; +import {OperatorInterface} from "./interfaces/OperatorInterface.sol"; +import {PointerInterface} from "./interfaces/PointerInterface.sol"; import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; /** @@ -14,6 +14,7 @@ import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol"; * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network */ +// solhint-disable custom-errors abstract contract ChainlinkClient { using Chainlink for Chainlink.Request; @@ -44,13 +45,13 @@ abstract contract ChainlinkClient { * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ - function buildChainlinkRequest( + function _buildChainlinkRequest( bytes32 specId, address callbackAddr, bytes4 callbackFunctionSignature ) internal pure returns (Chainlink.Request memory) { Chainlink.Request memory req; - return req.initialize(specId, callbackAddr, callbackFunctionSignature); + return req._initialize(specId, callbackAddr, callbackFunctionSignature); } /** @@ -59,12 +60,12 @@ abstract contract ChainlinkClient { * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ - function buildOperatorRequest( + function _buildOperatorRequest( bytes32 specId, bytes4 callbackFunctionSignature ) internal view returns (Chainlink.Request memory) { Chainlink.Request memory req; - return req.initialize(specId, address(this), callbackFunctionSignature); + return req._initialize(specId, address(this), callbackFunctionSignature); } /** @@ -74,8 +75,8 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendChainlinkRequestTo(address(s_oracle), req, payment); + function _sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { + return _sendChainlinkRequestTo(address(s_oracle), req, payment); } /** @@ -88,7 +89,7 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendChainlinkRequestTo( + function _sendChainlinkRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment @@ -117,8 +118,8 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { - return sendOperatorRequestTo(address(s_oracle), req, payment); + function _sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { + return _sendOperatorRequestTo(address(s_oracle), req, payment); } /** @@ -132,7 +133,7 @@ abstract contract ChainlinkClient { * @param payment The amount of LINK to send for the request * @return requestId The request ID */ - function sendOperatorRequestTo( + function _sendOperatorRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment @@ -182,7 +183,7 @@ abstract contract ChainlinkClient { * @param callbackFunc The callback function specified for the request * @param expiration The time of the expiration for the request */ - function cancelChainlinkRequest( + function _cancelChainlinkRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunc, @@ -199,7 +200,7 @@ abstract contract ChainlinkClient { * @dev starts at 1 in order to ensure consistent gas cost * @return returns the next request count to be used in a nonce */ - function getNextRequestCount() internal view returns (uint256) { + function _getNextRequestCount() internal view returns (uint256) { return s_requestCount; } @@ -207,7 +208,7 @@ abstract contract ChainlinkClient { * @notice Sets the stored oracle address * @param oracleAddress The address of the oracle contract */ - function setChainlinkOracle(address oracleAddress) internal { + function _setChainlinkOracle(address oracleAddress) internal { s_oracle = OperatorInterface(oracleAddress); } @@ -215,7 +216,7 @@ abstract contract ChainlinkClient { * @notice Sets the LINK token address * @param linkAddress The address of the LINK token contract */ - function setChainlinkToken(address linkAddress) internal { + function _setChainlinkToken(address linkAddress) internal { s_link = LinkTokenInterface(linkAddress); } @@ -223,15 +224,15 @@ abstract contract ChainlinkClient { * @notice Sets the Chainlink token address for the public * network as given by the Pointer contract */ - function setPublicChainlinkToken() internal { - setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); + function _setPublicChainlinkToken() internal { + _setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); } /** * @notice Retrieves the stored address of the LINK token * @return The address of the LINK token */ - function chainlinkTokenAddress() internal view returns (address) { + function _chainlinkTokenAddress() internal view returns (address) { return address(s_link); } @@ -239,7 +240,7 @@ abstract contract ChainlinkClient { * @notice Retrieves the stored address of the oracle contract * @return The address of the oracle contract */ - function chainlinkOracleAddress() internal view returns (address) { + function _chainlinkOracleAddress() internal view returns (address) { return address(s_oracle); } @@ -249,7 +250,10 @@ abstract contract ChainlinkClient { * @param oracleAddress The address of the oracle contract that will fulfill the request * @param requestId The request ID used for the response */ - function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { + function _addChainlinkExternalRequest( + address oracleAddress, + bytes32 requestId + ) internal notPendingRequest(requestId) { s_pendingRequests[requestId] = oracleAddress; } @@ -259,23 +263,23 @@ abstract contract ChainlinkClient { * @param ensAddress The address of the ENS contract * @param node The ENS node hash */ - function useChainlinkWithENS(address ensAddress, bytes32 node) internal { + function _useChainlinkWithENS(address ensAddress, bytes32 node) internal { s_ens = ENSInterface(ensAddress); s_ensNode = node; bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); - setChainlinkToken(resolver.addr(linkSubnode)); - updateChainlinkOracleWithENS(); + _setChainlinkToken(resolver.addr(linkSubnode)); + _updateChainlinkOracleWithENS(); } /** * @notice Sets the stored oracle contract with the address resolved by ENS * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously */ - function updateChainlinkOracleWithENS() internal { + function _updateChainlinkOracleWithENS() internal { bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); - setChainlinkOracle(resolver.addr(oracleSubnode)); + _setChainlinkOracle(resolver.addr(oracleSubnode)); } /** @@ -283,7 +287,7 @@ abstract contract ChainlinkClient { * @dev Use if the contract developer prefers methods instead of modifiers for validation * @param requestId The request ID for fulfillment */ - function validateChainlinkCallback( + function _validateChainlinkCallback( bytes32 requestId ) internal diff --git a/contracts/src/v0.8/Flags.sol b/contracts/src/v0.8/Flags.sol index c4d1d0e61cd..7cd5a54b0fd 100644 --- a/contracts/src/v0.8/Flags.sol +++ b/contracts/src/v0.8/Flags.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./shared/access/SimpleReadAccessController.sol"; -import "./shared/interfaces/AccessControllerInterface.sol"; -import "./interfaces/FlagsInterface.sol"; +import {SimpleReadAccessController} from "./shared/access/SimpleReadAccessController.sol"; +import {AccessControllerInterface} from "./shared/interfaces/AccessControllerInterface.sol"; +import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; /** * @title The Flags contract @@ -13,10 +13,11 @@ import "./interfaces/FlagsInterface.sol"; * to allow addresses to raise flags on themselves, so if you are subscribing to * FlagOn events you should filter for addresses you care about. */ +// solhint-disable custom-errors contract Flags is FlagsInterface, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; - mapping(address => bool) private flags; + mapping(address => bool) private s_flags; event FlagRaised(address indexed subject); event FlagLowered(address indexed subject); @@ -36,7 +37,7 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * false value indicates that no flag was raised. */ function getFlag(address subject) external view override checkAccess returns (bool) { - return flags[subject]; + return s_flags[subject]; } /** @@ -48,7 +49,7 @@ contract Flags is FlagsInterface, SimpleReadAccessController { function getFlags(address[] calldata subjects) external view override checkAccess returns (bool[] memory) { bool[] memory responses = new bool[](subjects.length); for (uint256 i = 0; i < subjects.length; i++) { - responses[i] = flags[subjects[i]]; + responses[i] = s_flags[subjects[i]]; } return responses; } @@ -60,9 +61,9 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * @param subject The contract address whose flag is being raised */ function raiseFlag(address subject) external override { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); + require(_allowedToRaiseFlags(), "Not allowed to raise flags"); - tryToRaiseFlag(subject); + _tryToRaiseFlag(subject); } /** @@ -72,10 +73,10 @@ contract Flags is FlagsInterface, SimpleReadAccessController { * @param subjects List of the contract addresses whose flag is being raised */ function raiseFlags(address[] calldata subjects) external override { - require(allowedToRaiseFlags(), "Not allowed to raise flags"); + require(_allowedToRaiseFlags(), "Not allowed to raise flags"); for (uint256 i = 0; i < subjects.length; i++) { - tryToRaiseFlag(subjects[i]); + _tryToRaiseFlag(subjects[i]); } } @@ -87,8 +88,8 @@ contract Flags is FlagsInterface, SimpleReadAccessController { for (uint256 i = 0; i < subjects.length; i++) { address subject = subjects[i]; - if (flags[subject]) { - flags[subject] = false; + if (s_flags[subject]) { + s_flags[subject] = false; emit FlagLowered(subject); } } @@ -110,13 +111,13 @@ contract Flags is FlagsInterface, SimpleReadAccessController { // PRIVATE - function allowedToRaiseFlags() private view returns (bool) { + function _allowedToRaiseFlags() private view returns (bool) { return msg.sender == owner() || raisingAccessController.hasAccess(msg.sender, msg.data); } - function tryToRaiseFlag(address subject) private { - if (!flags[subject]) { - flags[subject] = true; + function _tryToRaiseFlag(address subject) private { + if (!s_flags[subject]) { + s_flags[subject] = true; emit FlagRaised(subject); } } diff --git a/contracts/src/v0.8/PermissionedForwardProxy.sol b/contracts/src/v0.8/PermissionedForwardProxy.sol index 6206bd5420c..544f89065c0 100644 --- a/contracts/src/v0.8/PermissionedForwardProxy.sol +++ b/contracts/src/v0.8/PermissionedForwardProxy.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.6; -import "@openzeppelin/contracts/utils/Address.sol"; -import "./shared/access/ConfirmedOwner.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; /** * @title PermissionedForwardProxy diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index ea81719270b..35909ad87de 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./shared/access/ConfirmedOwner.sol"; -import "./interfaces/AggregatorValidatorInterface.sol"; -import "./interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "./shared/access/ConfirmedOwner.sol"; +import {AggregatorValidatorInterface} from "./interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "./interfaces/TypeAndVersionInterface.sol"; +// solhint-disable custom-errors contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface, ConfirmedOwner { /// @notice Uses a single storage slot to store the current address struct AggregatorConfiguration { @@ -97,6 +98,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface ValidatorConfiguration memory currentValidator = s_currentValidator; address currentValidatorAddress = address(currentValidator.target); require(currentValidatorAddress != address(0), "No validator set"); + // solhint-disable-next-line avoid-low-level-calls currentValidatorAddress.call( abi.encodeWithSelector( AggregatorValidatorInterface.validate.selector, @@ -108,6 +110,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface ); // If there is a new proposed validator, send the validate call to that validator also if (currentValidator.hasNewProposal) { + // solhint-disable-next-line avoid-low-level-calls address(s_proposedValidator).call( abi.encodeWithSelector( AggregatorValidatorInterface.validate.selector, diff --git a/contracts/src/v0.8/automation/KeeperBase.sol b/contracts/src/v0.8/automation/KeeperBase.sol index 448d4deacea..0e050d4aff3 100644 --- a/contracts/src/v0.8/automation/KeeperBase.sol +++ b/contracts/src/v0.8/automation/KeeperBase.sol @@ -3,4 +3,5 @@ * @notice This is a deprecated interface. Please use AutomationBase directly. */ pragma solidity ^0.8.0; +// solhint-disable-next-line no-unused-import import {AutomationBase as KeeperBase} from "./AutomationBase.sol"; diff --git a/contracts/src/v0.8/automation/KeeperCompatible.sol b/contracts/src/v0.8/automation/KeeperCompatible.sol index f5263eda7b9..6379fe526be 100644 --- a/contracts/src/v0.8/automation/KeeperCompatible.sol +++ b/contracts/src/v0.8/automation/KeeperCompatible.sol @@ -3,6 +3,9 @@ * @notice This is a deprecated interface. Please use AutomationCompatible directly. */ pragma solidity ^0.8.0; +// solhint-disable-next-line no-unused-import import {AutomationCompatible as KeeperCompatible} from "./AutomationCompatible.sol"; +// solhint-disable-next-line no-unused-import import {AutomationBase as KeeperBase} from "./AutomationBase.sol"; +// solhint-disable-next-line no-unused-import import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "./interfaces/AutomationCompatibleInterface.sol"; diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol index e47b33fc012..9c14ce69f48 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol @@ -109,7 +109,7 @@ contract MercuryRegistry is ConfirmedOwner, AutomationCompatibleInterface, Strea // Extracted from `checkUpkeep` for batching purposes. function revertForFeedLookup(string[] memory feeds) public view returns (bool, bytes memory) { - uint256 blockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 blockNumber = ChainSpecificUtil._getBlockNumber(); revert StreamsLookup(c_feedParamKey, feeds, c_timeParamKey, blockNumber, ""); } diff --git a/contracts/src/v0.8/automation/interfaces/KeeperCompatibleInterface.sol b/contracts/src/v0.8/automation/interfaces/KeeperCompatibleInterface.sol index d316722313e..b5ba8196c74 100644 --- a/contracts/src/v0.8/automation/interfaces/KeeperCompatibleInterface.sol +++ b/contracts/src/v0.8/automation/interfaces/KeeperCompatibleInterface.sol @@ -3,4 +3,5 @@ * @notice This is a deprecated interface. Please use AutomationCompatibleInterface directly. */ pragma solidity ^0.8.0; +// solhint-disable-next-line no-unused-import import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "./AutomationCompatibleInterface.sol"; diff --git a/contracts/src/v0.8/automation/interfaces/v1_2/KeeperRegistryInterface1_2.sol b/contracts/src/v0.8/automation/interfaces/v1_2/KeeperRegistryInterface1_2.sol index 124e279ab40..01f70ae9c7d 100644 --- a/contracts/src/v0.8/automation/interfaces/v1_2/KeeperRegistryInterface1_2.sol +++ b/contracts/src/v0.8/automation/interfaces/v1_2/KeeperRegistryInterface1_2.sol @@ -3,7 +3,11 @@ * @notice This is a deprecated interface. Please use AutomationRegistryInterface1_2 directly. */ pragma solidity ^0.8.0; +// solhint-disable-next-line no-unused-import import {Config, State} from "./AutomationRegistryInterface1_2.sol"; +// solhint-disable-next-line no-unused-import import {AutomationRegistryBaseInterface as KeeperRegistryBaseInterface} from "./AutomationRegistryInterface1_2.sol"; +// solhint-disable-next-line no-unused-import import {AutomationRegistryInterface as KeeperRegistryInterface} from "./AutomationRegistryInterface1_2.sol"; +// solhint-disable-next-line no-unused-import import {AutomationRegistryExecutableInterface as KeeperRegistryExecutableInterface} from "./AutomationRegistryInterface1_2.sol"; diff --git a/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol b/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol index cab4d61c5b9..a20fe3127a6 100644 --- a/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol +++ b/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol @@ -139,7 +139,10 @@ interface IKeeperRegistryMaster { bytes memory offchainConfig ) external; - function simulatePerformUpkeep(uint256 id, bytes memory performData) external returns (bool success, uint256 gasUsed); + function simulatePerformUpkeep( + uint256 id, + bytes memory performData + ) external view returns (bool success, uint256 gasUsed); function transferOwnership(address to) external; @@ -161,13 +164,14 @@ interface IKeeperRegistryMaster { uint256 id, bytes[] memory values, bytes memory extraData - ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); + ) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); function checkUpkeep( uint256 id, bytes memory triggerData ) external + view returns ( bool upkeepNeeded, bytes memory performData, @@ -182,6 +186,7 @@ interface IKeeperRegistryMaster { uint256 id ) external + view returns ( bool upkeepNeeded, bytes memory performData, @@ -375,5 +380,5 @@ interface KeeperRegistryBase2_1 { // THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: /* -[{"inputs":[{"internalType":"contract KeeperRegistryLogicB2_1","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MaxCheckDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MaxPerformDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"OwnerFundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct KeeperRegistryBase2_1.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract KeeperRegistryLogicB2_1","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkNative","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkNative","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"triggerType","type":"uint8"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum KeeperRegistryBase2_1.Mode","name":"mode","type":"uint8"},{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkNativeFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkNativeFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMode","outputs":[{"internalType":"enum KeeperRegistryBase2_1.Mode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum KeeperRegistryBase2_1.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct KeeperRegistryBase2_1.State","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct KeeperRegistryBase2_1.OnchainConfig","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct KeeperRegistryBase2_1.UpkeepInfo","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum KeeperRegistryBase2_1.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawOwnerFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] +[{"inputs":[{"internalType":"contract KeeperRegistryLogicB2_1","name":"logicA","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayHasNoEntries","type":"error"},{"inputs":[],"name":"CannotCancel","type":"error"},{"inputs":[],"name":"CheckDataExceedsLimit","type":"error"},{"inputs":[],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[],"name":"DuplicateEntry","type":"error"},{"inputs":[],"name":"DuplicateSigners","type":"error"},{"inputs":[],"name":"GasLimitCanOnlyIncrease","type":"error"},{"inputs":[],"name":"GasLimitOutsideRange","type":"error"},{"inputs":[],"name":"IncorrectNumberOfFaultyOracles","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSignatures","type":"error"},{"inputs":[],"name":"IncorrectNumberOfSigners","type":"error"},{"inputs":[],"name":"IndexOutOfRange","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MaxCheckDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MaxPerformDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyActiveSigners","type":"error"},{"inputs":[],"name":"OnlyActiveTransmitters","type":"error"},{"inputs":[],"name":"OnlyCallableByAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByLINKToken","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByOwnerOrRegistrar","type":"error"},{"inputs":[],"name":"OnlyCallableByPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedAdmin","type":"error"},{"inputs":[],"name":"OnlyCallableByProposedPayee","type":"error"},{"inputs":[],"name":"OnlyCallableByUpkeepPrivilegeManager","type":"error"},{"inputs":[],"name":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"RegistryPaused","type":"error"},{"inputs":[],"name":"RepeatedSigner","type":"error"},{"inputs":[],"name":"RepeatedTransmitter","type":"error"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"TargetCheckReverted","type":"error"},{"inputs":[],"name":"TooManyOracles","type":"error"},{"inputs":[],"name":"TranscoderNotSet","type":"error"},{"inputs":[],"name":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"AdminPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"previousConfigBlockNumber","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"configCount","type":"uint64"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"f","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"onchainConfig","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"DedupKeyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"FundsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"InsufficientFundsUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"amount","type":"uint96"}],"name":"OwnerFundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"payees","type":"address[]"}],"name":"PayeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"PayeeshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"transmitter","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"payee","type":"address"}],"name":"PaymentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"ReorgedUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"StaleUpkeepReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"Transmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"UpkeepAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint64","name":"atBlockHeight","type":"uint64"}],"name":"UpkeepCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"UpkeepCheckDataSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"gasLimit","type":"uint96"}],"name":"UpkeepGasLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"UpkeepMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"UpkeepOffchainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"uint96","name":"totalPayment","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasOverhead","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"UpkeepPerformed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"privilegeConfig","type":"bytes"}],"name":"UpkeepPrivilegeConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"importedFrom","type":"address"}],"name":"UpkeepReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"performGas","type":"uint32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"UpkeepRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"UpkeepTriggerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"UpkeepUnpaused","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDetails","outputs":[{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"blockNumber","type":"uint32"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestConfigDigestAndEpoch","outputs":[{"internalType":"bool","name":"scanLogs","type":"bool"},{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"internalType":"bytes","name":"onchainConfigBytes","type":"bytes"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct KeeperRegistryBase2_1.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfigTypeSafe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"performData","type":"bytes"}],"name":"simulatePerformUpkeep","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[3]","name":"reportContext","type":"bytes32[3]"},{"internalType":"bytes","name":"rawReport","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"transmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract KeeperRegistryLogicB2_1","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes[]","name":"values","type":"bytes[]"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"checkCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkNative","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"checkUpkeep","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"uint256","name":"fastGasWei","type":"uint256"},{"internalType":"uint256","name":"linkNative","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"executeCallback","outputs":[{"internalType":"bool","name":"upkeepNeeded","type":"bool"},{"internalType":"bytes","name":"performData","type":"bytes"},{"internalType":"enum KeeperRegistryBase2_1.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"destination","type":"address"}],"name":"migrateUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedUpkeeps","type":"bytes"}],"name":"receiveUpkeeps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"triggerType","type":"uint8"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"registerUpkeep","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum KeeperRegistryBase2_1.Mode","name":"mode","type":"uint8"},{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkNativeFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"}],"name":"acceptPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"acceptUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getActiveUpkeepIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"getAdminPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutomationForwarderLogic","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBalance","outputs":[{"internalType":"uint96","name":"balance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getFastGasFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getForwarder","outputs":[{"internalType":"contract IAutomationForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkNativeFeedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLogGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"getMaxPaymentForGas","outputs":[{"internalType":"uint96","name":"maxPayment","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalance","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getMinBalanceForUpkeep","outputs":[{"internalType":"uint96","name":"minBalance","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMode","outputs":[{"internalType":"enum KeeperRegistryBase2_1.Mode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum KeeperRegistryBase2_1.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPerPerformByteGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getPerSignerGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getSignerInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"components":[{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint96","name":"ownerLinkBalance","type":"uint96"},{"internalType":"uint256","name":"expectedLinkBalance","type":"uint256"},{"internalType":"uint96","name":"totalPremium","type":"uint96"},{"internalType":"uint256","name":"numUpkeeps","type":"uint256"},{"internalType":"uint32","name":"configCount","type":"uint32"},{"internalType":"uint32","name":"latestConfigBlockNumber","type":"uint32"},{"internalType":"bytes32","name":"latestConfigDigest","type":"bytes32"},{"internalType":"uint32","name":"latestEpoch","type":"uint32"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct KeeperRegistryBase2_1.State","name":"state","type":"tuple"},{"components":[{"internalType":"uint32","name":"paymentPremiumPPB","type":"uint32"},{"internalType":"uint32","name":"flatFeeMicroLink","type":"uint32"},{"internalType":"uint32","name":"checkGasLimit","type":"uint32"},{"internalType":"uint24","name":"stalenessSeconds","type":"uint24"},{"internalType":"uint16","name":"gasCeilingMultiplier","type":"uint16"},{"internalType":"uint96","name":"minUpkeepSpend","type":"uint96"},{"internalType":"uint32","name":"maxPerformGas","type":"uint32"},{"internalType":"uint32","name":"maxCheckDataSize","type":"uint32"},{"internalType":"uint32","name":"maxPerformDataSize","type":"uint32"},{"internalType":"uint32","name":"maxRevertDataSize","type":"uint32"},{"internalType":"uint256","name":"fallbackGasPrice","type":"uint256"},{"internalType":"uint256","name":"fallbackLinkPrice","type":"uint256"},{"internalType":"address","name":"transcoder","type":"address"},{"internalType":"address[]","name":"registrars","type":"address[]"},{"internalType":"address","name":"upkeepPrivilegeManager","type":"address"}],"internalType":"struct KeeperRegistryBase2_1.OnchainConfig","name":"config","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"},{"internalType":"uint8","name":"f","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"query","type":"address"}],"name":"getTransmitterInfo","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"uint96","name":"lastCollected","type":"uint96"},{"internalType":"address","name":"payee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum KeeperRegistryBase2_1.Trigger","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getUpkeep","outputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint32","name":"performGas","type":"uint32"},{"internalType":"bytes","name":"checkData","type":"bytes"},{"internalType":"uint96","name":"balance","type":"uint96"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"uint64","name":"maxValidBlocknumber","type":"uint64"},{"internalType":"uint32","name":"lastPerformedBlockNumber","type":"uint32"},{"internalType":"uint96","name":"amountSpent","type":"uint96"},{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"internalType":"struct KeeperRegistryBase2_1.UpkeepInfo","name":"upkeepInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepPrivilegeConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getUpkeepTriggerConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"pauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setAdminPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"payees","type":"address[]"}],"name":"setPayees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"},{"internalType":"enum KeeperRegistryBase2_1.MigrationPermission","name":"permission","type":"uint8"}],"name":"setPeerRegistryMigrationPermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"newCheckData","type":"bytes"}],"name":"setUpkeepCheckData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"name":"setUpkeepGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setUpkeepOffchainConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"},{"internalType":"bytes","name":"newPrivilegeConfig","type":"bytes"}],"name":"setUpkeepPrivilegeConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transmitter","type":"address"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferPayeeship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"proposed","type":"address"}],"name":"transferUpkeepAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawOwnerFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawPayment","outputs":[],"stateMutability":"nonpayable","type":"function"}] */ diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol b/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol new file mode 100644 index 00000000000..6fe41607f75 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/KeeperBase.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +contract KeeperBase { + /** + * @notice method that allows it to be simulated via eth_call by checking that + * the sender is the zero address. + */ + function preventExecution() internal view { + require(tx.origin == address(0), "only for simulated backend"); + } + + /** + * @notice modifier that allows it to be simulated via eth_call by checking + * that the sender is the zero address. + */ + modifier cannotExecute() { + preventExecution(); + _; + } +} diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol b/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol new file mode 100644 index 00000000000..113f5ef6a55 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/KeeperCompatibleInterface.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.16; + +interface KeeperCompatibleInterface { + /** + * @notice method that is simulated by the keepers to see if any work actually + * needs to be performed. This method does does not actually need to be + * executable, and since it is only ever simulated it can consume lots of gas. + * @dev To ensure that it is never called, you may want to add the + * cannotExecute modifier from KeeperBase to your implementation of this + * method. + * @param checkData specified in the upkeep registration so it is always the + * same for a registered upkeep. This can easily be broken down into specific + * arguments using `abi.decode`, so multiple upkeeps can be registered on the + * same contract and easily differentiated by the contract. + * @return upkeepNeeded boolean to indicate whether the keeper should call + * performUpkeep or not. + * @return performData bytes that the keeper should call performUpkeep with, if + * upkeep is needed. If you would like to encode data to decode later, try + * `abi.encode`. + */ + function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData); + + /** + * @notice method that is actually executed by the keepers, via the registry. + * The data returned by the checkUpkeep simulation will be passed into + * this method to actually be executed. + * @dev The input to this method should not be trusted, and the caller of the + * method should not even be restricted to any single registry. Anyone should + * be able call it, and the input should be validated, there is no guarantee + * that the data passed in is the performData returned from checkUpkeep. This + * could happen due to malicious keepers, racing keepers, or simply a state + * change while the performUpkeep transaction is waiting for confirmation. + * Always validate the data passed in. + * @param performData is the data which was passed back from the checkData + * simulation. If it is encoded, it can easily be decoded into other types by + * calling `abi.decode`. This data should not be trusted, and should be + * validated against the contract's current state. + */ + function performUpkeep(bytes calldata performData) external; +} diff --git a/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol b/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol new file mode 100644 index 00000000000..ba4694234a9 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/KeeperConsumer.sol @@ -0,0 +1,26 @@ +pragma solidity 0.8.16; + +import "./KeeperCompatibleInterface.sol"; +import "./KeeperBase.sol"; + +contract KeeperConsumer is KeeperCompatibleInterface, KeeperBase { + uint public counter; + uint public immutable interval; + uint public lastTimeStamp; + + constructor(uint updateInterval) public { + interval = updateInterval; + lastTimeStamp = block.timestamp; + counter = 0; + } + + function checkUpkeep( + bytes calldata checkData + ) external view override cannotExecute returns (bool upkeepNeeded, bytes memory performData) { + return (true, checkData); + } + + function performUpkeep(bytes calldata performData) external override { + counter = counter + 1; + } +} diff --git a/integration-tests/contracts/ethereum/src/KeeperConsumerPerformance.sol b/contracts/src/v0.8/automation/testhelpers/KeeperConsumerPerformance.sol similarity index 93% rename from integration-tests/contracts/ethereum/src/KeeperConsumerPerformance.sol rename to contracts/src/v0.8/automation/testhelpers/KeeperConsumerPerformance.sol index 4d763f7276e..5b7f57e116e 100644 --- a/integration-tests/contracts/ethereum/src/KeeperConsumerPerformance.sol +++ b/contracts/src/v0.8/automation/testhelpers/KeeperConsumerPerformance.sol @@ -1,4 +1,4 @@ -pragma solidity 0.7.6; +pragma solidity 0.8.16; contract KeeperConsumerPerformance { event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber); @@ -13,7 +13,12 @@ contract KeeperConsumerPerformance { uint256 public count = 0; - constructor(uint256 _testRange, uint256 _averageEligibilityCadence, uint256 _checkGasToBurn, uint256 _performGasToBurn) { + constructor( + uint256 _testRange, + uint256 _averageEligibilityCadence, + uint256 _checkGasToBurn, + uint256 _performGasToBurn + ) { testRange = _testRange; averageEligibilityCadence = _averageEligibilityCadence; checkGasToBurn = _checkGasToBurn; @@ -80,4 +85,4 @@ contract KeeperConsumerPerformance { function rand() private view returns (uint256) { return uint256(keccak256(abi.encode(blockhash(block.number - 1), address(this)))); } -} \ No newline at end of file +} diff --git a/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol index eb7f3c48f69..5bdea03139c 100644 --- a/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol +++ b/contracts/src/v0.8/automation/testhelpers/LogTriggeredStreamsLookup.sol @@ -25,6 +25,7 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt bytes blob, bytes verified ); + event LimitOrderExecuted(uint256 indexed orderId, uint256 indexed amount, address indexed exchange); // keccak(LimitOrderExecuted(uint256,uint256,address)) => 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); IVerifierProxy internal constant VERIFIER = IVerifierProxy(0x09DFf56A4fF44e0f4436260A04F5CFa65636A481); @@ -40,10 +41,17 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt string[] public feedsHex = ["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]; string public feedParamKey = "feedIdHex"; string public timeParamKey = "blockNumber"; + uint256 public counter; constructor(bool _useArbitrumBlockNum, bool _verify) { useArbitrumBlockNum = _useArbitrumBlockNum; verify = _verify; + counter = 0; + } + + function start() public { + // need an initial event to begin the cycle + emit LimitOrderExecuted(1, 100, address(0x0)); } function setTimeParamKey(string memory timeParam) external { @@ -74,20 +82,34 @@ contract LogTriggeredStreamsLookup is ILogAutomation, StreamsLookupCompatibleInt bytes memory t3 = abi.encodePacked(log.topics[3]); address exchange = abi.decode(t3, (address)); - revert StreamsLookup(feedParamKey, feedsHex, timeParamKey, blockNum, abi.encode(orderId, amount, exchange)); + revert StreamsLookup( + feedParamKey, + feedsHex, + timeParamKey, + blockNum, + abi.encode(orderId, amount, exchange, executedSig) + ); } revert("could not find matching event sig"); } function performUpkeep(bytes calldata performData) external override { (bytes[] memory values, bytes memory extraData) = abi.decode(performData, (bytes[], bytes)); - (uint256 orderId, uint256 amount, address exchange) = abi.decode(extraData, (uint256, uint256, address)); + (uint256 orderId, uint256 amount, address exchange, bytes32 logTopic0) = abi.decode( + extraData, + (uint256, uint256, address, bytes32) + ); bytes memory verifiedResponse = ""; if (verify) { verifiedResponse = VERIFIER.verify(values[0]); } + counter = counter + 1; + if (logTopic0 == executedSig) { + emit LimitOrderExecuted(1, 100, address(0x0)); + } + emit PerformingLogTriggerUpkeep( tx.origin, orderId, diff --git a/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol b/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol new file mode 100644 index 00000000000..03c57ea8e41 --- /dev/null +++ b/contracts/src/v0.8/automation/testhelpers/PerformDataChecker.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.16; + +import "./KeeperCompatibleInterface.sol"; + +contract PerformDataChecker is KeeperCompatibleInterface { + uint256 public counter; + bytes public s_expectedData; + + constructor(bytes memory expectedData) { + s_expectedData = expectedData; + } + + function setExpectedData(bytes calldata expectedData) external { + s_expectedData = expectedData; + } + + function checkUpkeep( + bytes calldata checkData + ) external view override returns (bool upkeepNeeded, bytes memory performData) { + return (keccak256(checkData) == keccak256(s_expectedData), checkData); + } + + function performUpkeep(bytes calldata performData) external override { + if (keccak256(performData) == keccak256(s_expectedData)) { + counter++; + } + } +} diff --git a/integration-tests/contracts/ethereum/src/UpkeepPerformCounterRestrictive.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepPerformCounterRestrictive.sol similarity index 99% rename from integration-tests/contracts/ethereum/src/UpkeepPerformCounterRestrictive.sol rename to contracts/src/v0.8/automation/testhelpers/UpkeepPerformCounterRestrictive.sol index 35e28584a09..3aa345ab458 100644 --- a/integration-tests/contracts/ethereum/src/UpkeepPerformCounterRestrictive.sol +++ b/contracts/src/v0.8/automation/testhelpers/UpkeepPerformCounterRestrictive.sol @@ -1,4 +1,4 @@ -pragma solidity 0.7.6; +pragma solidity 0.8.16; contract UpkeepPerformCounterRestrictive { event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber); diff --git a/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol index 69f36f92cc6..61a6e882d81 100644 --- a/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.4; import "../../shared/access/ConfirmedOwner.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; -import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol"; -import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title The ERC20BalanceMonitor contract. diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index af24d86e3c8..cff09aaebbd 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.6; import "../../shared/access/ConfirmedOwner.sol"; import "../interfaces/KeeperCompatibleInterface.sol"; -import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol"; -import "../../vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; +import "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableMap.sol"; interface IAggregatorProxy { diff --git a/contracts/src/v0.8/automation/v1_3/KeeperRegistry1_3.sol b/contracts/src/v0.8/automation/v1_3/KeeperRegistry1_3.sol index c40f79f85b4..dbef8d77d19 100644 --- a/contracts/src/v0.8/automation/v1_3/KeeperRegistry1_3.sol +++ b/contracts/src/v0.8/automation/v1_3/KeeperRegistry1_3.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "./KeeperRegistryBase1_3.sol"; import "./KeeperRegistryLogic1_3.sol"; -import {AutomationRegistryExecutableInterface} from "../interfaces/v1_3/AutomationRegistryInterface1_3.sol"; +import {AutomationRegistryExecutableInterface, State} from "../interfaces/v1_3/AutomationRegistryInterface1_3.sol"; import "../interfaces/MigratableKeeperRegistryInterface.sol"; import "../../interfaces/TypeAndVersionInterface.sol"; import "../../shared/interfaces/IERC677Receiver.sol"; diff --git a/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol b/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol index d63f6f40e88..6328b651671 100644 --- a/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol +++ b/contracts/src/v0.8/automation/v1_3/KeeperRegistryBase1_3.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; import "../../vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; import "../ExecutionPrevention.sol"; -import {Config, State, Upkeep} from "../interfaces/v1_3/AutomationRegistryInterface1_3.sol"; +import {Config, Upkeep} from "../interfaces/v1_3/AutomationRegistryInterface1_3.sol"; import "../../shared/access/ConfirmedOwner.sol"; import "../../interfaces/AggregatorV3Interface.sol"; import "../../shared/interfaces/LinkTokenInterface.sol"; diff --git a/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol b/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol index 34781f18258..7db02e72e73 100644 --- a/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol +++ b/contracts/src/v0.8/automation/v2_0/KeeperRegistry2_0.sol @@ -5,7 +5,7 @@ import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol"; import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import "./KeeperRegistryBase2_0.sol"; -import {AutomationRegistryExecutableInterface, UpkeepInfo} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; +import {AutomationRegistryExecutableInterface, UpkeepInfo, State, OnchainConfig, UpkeepFailureReason} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; import "../interfaces/MigratableKeeperRegistryInterface.sol"; import "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; import "../../shared/interfaces/IERC677Receiver.sol"; diff --git a/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol b/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol index c1e9a279f84..14e9b204475 100644 --- a/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol +++ b/contracts/src/v0.8/automation/v2_0/KeeperRegistryBase2_0.sol @@ -6,7 +6,6 @@ import "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; import "../../vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; import {ArbSys} from "../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; import "../ExecutionPrevention.sol"; -import {OnchainConfig, State, UpkeepFailureReason} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; import "../../shared/access/ConfirmedOwner.sol"; import "../../interfaces/AggregatorV3Interface.sol"; import "../../shared/interfaces/LinkTokenInterface.sol"; diff --git a/contracts/src/v0.8/automation/v2_0/KeeperRegistryLogic2_0.sol b/contracts/src/v0.8/automation/v2_0/KeeperRegistryLogic2_0.sol index 7e6134a178f..7eacc3cb61e 100644 --- a/contracts/src/v0.8/automation/v2_0/KeeperRegistryLogic2_0.sol +++ b/contracts/src/v0.8/automation/v2_0/KeeperRegistryLogic2_0.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.6; import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; import "./KeeperRegistryBase2_0.sol"; +import {UpkeepFailureReason} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; import "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; import "../interfaces/UpkeepTranscoderInterfaceV2.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/AutomationUtils2_1.sol b/contracts/src/v0.8/automation/v2_1/AutomationUtils2_1.sol index ed19b450d8b..f6ba913b2fb 100644 --- a/contracts/src/v0.8/automation/v2_1/AutomationUtils2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/AutomationUtils2_1.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.16; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; -import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; +import {Log} from "../interfaces/ILogAutomation.sol"; /** * @notice this file exposes structs that are otherwise internal to the automation registry diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol index bb287c3c731..2f96df6d572 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistry2_1.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import {Proxy} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol"; import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol"; import {Chainable} from "../Chainable.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol index 86942f3108d..f5d89de5467 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistryBase2_1.sol @@ -14,7 +14,7 @@ import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; import {KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol"; -import {UpkeepTranscoderInterface, UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol"; +import {UpkeepFormat} from "../interfaces/UpkeepTranscoderInterface.sol"; /** * @notice Base Keeper Registry contract, contains shared logic between diff --git a/contracts/src/v0.8/automation/v2_1/README.md b/contracts/src/v0.8/automation/v2_1/README.md index 865f2d74e01..43c71daae76 100644 --- a/contracts/src/v0.8/automation/v2_1/README.md +++ b/contracts/src/v0.8/automation/v2_1/README.md @@ -34,10 +34,6 @@ graph LR The Master Interface is a deduped combination of all the interfaces from all contracts in the chain. We generate this interface programatically using the script `generate-automation-master-interface.ts`. This process is not a hardened one. Users of this script should take great care to ensure it's efficacy. -### Future Improvements - -- We could use this script to change `checkUpkeep` from an executable function to a "view" function in the master interface - this would make interacting with the contract simpler in tests and (maybe) also from the core node. - [size-limit-eip]: https://eips.ethereum.org/EIPS/eip-170 [fallback]: https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function [delegatecall]: https://docs.soliditylang.org/en/v0.8.12/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries diff --git a/contracts/src/v0.8/automation/v2_1/UpkeepTranscoder4_0.sol b/contracts/src/v0.8/automation/v2_1/UpkeepTranscoder4_0.sol index 727a3dd33ad..53b681d4cc1 100644 --- a/contracts/src/v0.8/automation/v2_1/UpkeepTranscoder4_0.sol +++ b/contracts/src/v0.8/automation/v2_1/UpkeepTranscoder4_0.sol @@ -6,7 +6,6 @@ import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfa import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; import {KeeperRegistryBase2_1 as R21} from "./KeeperRegistryBase2_1.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; -import {AutomationRegistryBaseInterface, UpkeepInfo} from "../interfaces/v2_0/AutomationRegistryInterface2_0.sol"; enum RegistryVersion { V12, diff --git a/contracts/src/v0.8/dev/BlockhashStore.sol b/contracts/src/v0.8/dev/BlockhashStore.sol deleted file mode 100644 index 74a4fc0ce47..00000000000 --- a/contracts/src/v0.8/dev/BlockhashStore.sol +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.6; - -import "../ChainSpecificUtil.sol"; - -/** - * @title BlockhashStore - * @notice This contract provides a way to access blockhashes older than - * the 256 block limit imposed by the BLOCKHASH opcode. - * You may assume that any blockhash stored by the contract is correct. - * Note that the contract depends on the format of serialized Ethereum - * blocks. If a future hardfork of Ethereum changes that format, the - * logic in this contract may become incorrect and an updated version - * would have to be deployed. - */ -contract BlockhashStore { - mapping(uint => bytes32) internal s_blockhashes; - - /** - * @notice stores blockhash of a given block, assuming it is available through BLOCKHASH - * @param n the number of the block whose blockhash should be stored - */ - function store(uint256 n) public { - bytes32 h = ChainSpecificUtil.getBlockhash(uint64(n)); - require(h != 0x0, "blockhash(n) failed"); - s_blockhashes[n] = h; - } - - /** - * @notice stores blockhash of the earliest block still available through BLOCKHASH. - */ - function storeEarliest() external { - store(ChainSpecificUtil.getBlockNumber() - 256); - } - - /** - * @notice stores blockhash after verifying blockheader of child/subsequent block - * @param n the number of the block whose blockhash should be stored - * @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking - * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. - */ - function storeVerifyHeader(uint256 n, bytes memory header) public { - require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); - - // At this point, we know that header is the correct blockheader for block n+1. - - // The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block. - // Based on how rlp works, we know that blockheaders always have the following form: - // 0xf9____a0PARENTHASH... - // ^ ^ ^ - // | | | - // | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH. - // | | - // | +--- 2 bytes containing the sum of the lengths of the encoded list items - // | - // +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes. - // - // As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header. - - bytes32 parentHash; - assembly { - parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array - // + 4 byte offset of PARENTHASH (see above) - } - - s_blockhashes[n] = parentHash; - } - - /** - * @notice gets a blockhash from the store. If no hash is known, this function reverts. - * @param n the number of the block whose blockhash should be returned - */ - function getBlockhash(uint256 n) external view returns (bytes32) { - bytes32 h = s_blockhashes[n]; - require(h != 0x0, "blockhash not found in store"); - return h; - } -} diff --git a/contracts/src/v0.8/dev/DerivedPriceFeed.sol b/contracts/src/v0.8/dev/DerivedPriceFeed.sol deleted file mode 100644 index 73f8e8c2202..00000000000 --- a/contracts/src/v0.8/dev/DerivedPriceFeed.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import "../interfaces/AggregatorV3Interface.sol"; - -/** - * Network: Fantom Testnet - * Base: LINK/USD - * Base Address: 0x6d5689Ad4C1806D1BA0c70Ab95ebe0Da6B204fC5 - * Quote: FTM/USD - * Quote Address: 0xe04676B9A9A2973BCb0D1478b5E1E9098BBB7f3D - * Decimals: 18 - * - * Network: AVAX Testnet - * Base: LINK/USD - * Base Address: 0x34C4c526902d88a3Aa98DB8a9b802603EB1E3470 - * Quote: AVAX/USD - * Quote Address: 0x5498BB86BC934c8D34FDA08E81D444153d0D06aD - * Decimals: 18 - * - * Chainlink Data Feeds can be used in combination to derive denominated price pairs in other - * currencies. - * - * If you require a denomination other than what is provided, you can use two data feeds to derive - * the pair that you need. - * - * For example, if you needed a LINK / FTM price, you could take the LINK / USD feed and the - * FTM / USD feed and derive LINK / FTM using division. - * (LINK/USD)/(FTM/USD) = LINK/FTM - */ -contract DerivedPriceFeed is AggregatorV3Interface { - uint256 public constant override version = 0; - - AggregatorV3Interface public immutable BASE; - AggregatorV3Interface public immutable QUOTE; - uint8 public immutable DECIMALS; - - constructor(address _base, address _quote, uint8 _decimals) { - require(_decimals > uint8(0) && _decimals <= uint8(18), "Invalid _decimals"); - DECIMALS = _decimals; - BASE = AggregatorV3Interface(_base); - QUOTE = AggregatorV3Interface(_quote); - } - - function decimals() external view override returns (uint8) { - return DECIMALS; - } - - function getRoundData(uint80) external pure override returns (uint80, int256, uint256, uint256, uint80) { - revert("not implemented - use latestRoundData()"); - } - - function description() external pure override returns (string memory) { - return "DerivedPriceFeed.sol"; - } - - function latestRoundData() - external - view - override - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - return (uint80(0), getDerivedPrice(), block.timestamp, block.timestamp, uint80(0)); - } - - // https://docs.chain.link/docs/get-the-latest-price/#getting-a-different-price-denomination - function getDerivedPrice() internal view returns (int256) { - (, int256 basePrice, , , ) = BASE.latestRoundData(); - uint8 baseDecimals = BASE.decimals(); - basePrice = scalePrice(basePrice, baseDecimals, DECIMALS); - - (, int256 quotePrice, , , ) = QUOTE.latestRoundData(); - uint8 quoteDecimals = QUOTE.decimals(); - quotePrice = scalePrice(quotePrice, quoteDecimals, DECIMALS); - - return (basePrice * int256(10 ** uint256(DECIMALS))) / quotePrice; - } - - function scalePrice(int256 _price, uint8 _priceDecimals, uint8 _decimals) internal pure returns (int256) { - if (_priceDecimals < _decimals) { - return _price * int256(10 ** uint256(_decimals - _priceDecimals)); - } else if (_priceDecimals > _decimals) { - return _price / int256(10 ** uint256(_priceDecimals - _decimals)); - } - return _price; - } -} diff --git a/contracts/src/v0.8/dev/ocr2/OCR2Abstract.sol b/contracts/src/v0.8/dev/ocr2/OCR2Abstract.sol deleted file mode 100644 index a1066ffcf5e..00000000000 --- a/contracts/src/v0.8/dev/ocr2/OCR2Abstract.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../../interfaces/TypeAndVersionInterface.sol"; - -abstract contract OCR2Abstract is TypeAndVersionInterface { - // Maximum number of oracles the offchain reporting protocol is designed for - uint256 internal constant maxNumOracles = 31; - - /** - * @notice triggers a new run of the offchain reporting protocol - * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis - * @param configDigest configDigest of this configuration - * @param configCount ordinal number of this config setting among all config settings over the life of this contract - * @param signers ith element is address ith oracle uses to sign a report - * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method - * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ - event ConfigSet( - uint32 previousConfigBlockNumber, - bytes32 configDigest, - uint64 configCount, - address[] signers, - address[] transmitters, - uint8 f, - bytes onchainConfig, - uint64 offchainConfigVersion, - bytes offchainConfig - ); - - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param signers addresses with which oracles sign the reports - * @param transmitters addresses oracles use to transmit the reports - * @param f number of faulty oracles the system can tolerate - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version number for offchainEncoding schema - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ - function setConfig( - address[] memory signers, - address[] memory transmitters, - uint8 f, - bytes memory onchainConfig, - uint64 offchainConfigVersion, - bytes memory offchainConfig - ) external virtual; - - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) - */ - function latestConfigDetails() - external - view - virtual - returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); - - function _configDigestFromConfigData( - uint256 chainId, - address contractAddress, - uint64 configCount, - address[] memory signers, - address[] memory transmitters, - uint8 f, - bytes memory onchainConfig, - uint64 offchainConfigVersion, - bytes memory offchainConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - chainId, - contractAddress, - configCount, - signers, - transmitters, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - - /** - * @notice optionally emited to indicate the latest configDigest and epoch for - which a report was successfully transmited. Alternatively, the contract may - use latestConfigDigestAndEpoch with scanLogs set to false. - */ - event Transmitted(bytes32 configDigest, uint32 epoch); - - /** - * @notice optionally returns the latest configDigest and epoch for which a - report was successfully transmitted. Alternatively, the contract may return - scanLogs set to true and use Transmitted events to provide this information - to offchain watchers. - * @return scanLogs indicates whether to rely on the configDigest and epoch - returned or whether to scan logs for the Transmitted event instead. - * @return configDigest - * @return epoch - */ - function latestConfigDigestAndEpoch() - external - view - virtual - returns (bool scanLogs, bytes32 configDigest, uint32 epoch); - - /** - * @notice transmit is called to post a new report to the contract - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ - function transmit( - // NOTE: If these parameters are changed, expectedMsgDataLength and/or - // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly - bytes32[3] calldata reportContext, - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss, - bytes32 rawVs // signatures - ) external virtual; -} diff --git a/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol b/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol new file mode 100644 index 00000000000..a24cbee504c --- /dev/null +++ b/contracts/src/v0.8/dev/shared/interfaces/OwnableInterface.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface OwnableInterface { + function owner() external returns (address); + + function transferOwnership(address recipient) external; + + function acceptOwnership() external; +} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/Functions.sol b/contracts/src/v0.8/functions/dev/v0_0_0/Functions.sol deleted file mode 100644 index 478149d8dda..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/Functions.sol +++ /dev/null @@ -1,152 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {CBOR, Buffer} from "../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; - -/** - * @title Library for Chainlink Functions - */ -library Functions { - uint256 internal constant DEFAULT_BUFFER_SIZE = 256; - - using CBOR for Buffer.buffer; - - enum Location { - Inline, - Remote, - DONHosted - } - - enum CodeLanguage { - JavaScript - // In future version we may add other languages - } - - struct Request { - Location codeLocation; - Location secretsLocation; - CodeLanguage language; - string source; // Source code for Location.Inline, url for Location.Remote or slot decimal number for Location.DONHosted - bytes secrets; // Encrypted urls for Location.Remote or CBOR encoded slotid+version for Location.DONHosted, use addDONHostedSecrets() - string[] args; - } - - error EmptySource(); - error EmptyUrl(); - error EmptySecrets(); - error EmptyArgs(); - error NoInlineSecrets(); - - /** - * @notice Encodes a Request to CBOR encoded bytes - * @param self The request to encode - * @return CBOR encoded bytes - */ - function encodeCBOR(Request memory self) internal pure returns (bytes memory) { - CBOR.CBORBuffer memory buffer; - Buffer.init(buffer.buf, DEFAULT_BUFFER_SIZE); - - CBOR.writeString(buffer, "codeLocation"); - CBOR.writeUInt256(buffer, uint256(self.codeLocation)); - - CBOR.writeString(buffer, "language"); - CBOR.writeUInt256(buffer, uint256(self.language)); - - CBOR.writeString(buffer, "source"); - CBOR.writeString(buffer, self.source); - - if (self.args.length > 0) { - CBOR.writeString(buffer, "args"); - CBOR.startArray(buffer); - for (uint256 i = 0; i < self.args.length; i++) { - CBOR.writeString(buffer, self.args[i]); - } - CBOR.endSequence(buffer); - } - - if (self.secrets.length > 0) { - if (self.secretsLocation == Location.Inline) { - revert NoInlineSecrets(); - } - CBOR.writeString(buffer, "secretsLocation"); - CBOR.writeUInt256(buffer, uint256(self.secretsLocation)); - CBOR.writeString(buffer, "secrets"); - CBOR.writeBytes(buffer, self.secrets); - } - - return buffer.buf.buf; - } - - /** - * @notice Initializes a Chainlink Functions Request - * @dev Sets the codeLocation and code on the request - * @param self The uninitialized request - * @param location The user provided source code location - * @param language The programming language of the user code - * @param source The user provided source code or a url - */ - function initializeRequest( - Request memory self, - Location location, - CodeLanguage language, - string memory source - ) internal pure { - if (bytes(source).length == 0) revert EmptySource(); - - self.codeLocation = location; - self.language = language; - self.source = source; - } - - /** - * @notice Initializes a Chainlink Functions Request - * @dev Simplified version of initializeRequest for PoC - * @param self The uninitialized request - * @param javaScriptSource The user provided JS code (must not be empty) - */ - function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { - initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); - } - - /** - * @notice Adds Remote user encrypted secrets to a Request - * @param self The initialized request - * @param encryptedSecretsURLs Encrypted comma-separated string of URLs pointing to off-chain secrets - */ - function addRemoteSecrets(Request memory self, bytes memory encryptedSecretsURLs) internal pure { - if (encryptedSecretsURLs.length == 0) revert EmptySecrets(); - - self.secretsLocation = Location.Remote; - self.secrets = encryptedSecretsURLs; - } - - /** - * @notice Adds DON-hosted secrets reference to a Request - * @param self The initialized request - * @param slotID Slot ID of the user's secrets hosted on DON - * @param version User data version (for the slotID) - */ - function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { - CBOR.CBORBuffer memory buffer; - Buffer.init(buffer.buf, DEFAULT_BUFFER_SIZE); - - CBOR.writeString(buffer, "slotID"); - CBOR.writeUInt64(buffer, slotID); - CBOR.writeString(buffer, "version"); - CBOR.writeUInt64(buffer, version); - - self.secretsLocation = Location.DONHosted; - self.secrets = buffer.buf.buf; - } - - /** - * @notice Adds args for the user run function - * @param self The initialized request - * @param args The array of args (must not be empty) - */ - function addArgs(Request memory self, string[] memory args) internal pure { - if (args.length == 0) revert EmptyArgs(); - - self.args = args; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsBillingRegistry.sol b/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsBillingRegistry.sol deleted file mode 100644 index 3488af55cca..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsBillingRegistry.sol +++ /dev/null @@ -1,842 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; -import {IFunctionsBillingRegistry} from "./interfaces/IFunctionsBillingRegistry.sol"; -import {IFunctionsOracle} from "./interfaces/IFunctionsOracle.sol"; -import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; -import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; -import {IAuthorizedOriginReceiver} from "./accessControl/interfaces/IAuthorizedOriginReceiver.sol"; -import {ConfirmedOwnerUpgradeable} from "./accessControl/ConfirmedOwnerUpgradeable.sol"; -import {AuthorizedReceiver} from "./accessControl/AuthorizedReceiver.sol"; -import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -import {PausableUpgradeable} from "../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol"; -import {Initializable} from "../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Billing Registry contract - * @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsBillingRegistry is - Initializable, - ConfirmedOwnerUpgradeable, - PausableUpgradeable, - IFunctionsBillingRegistry, - IERC677Receiver, - AuthorizedReceiver -{ - LinkTokenInterface private LINK; - AggregatorV3Interface private LINK_ETH_FEED; - IAuthorizedOriginReceiver private ORACLE_WITH_ALLOWLIST; - - // We need to maintain a list of consuming addresses. - // This bound ensures we are able to loop over them as needed. - // Should a user require more consumers, they can use multiple subscriptions. - uint16 public constant MAX_CONSUMERS = 100; - - error TooManyConsumers(); - error InsufficientBalance(); - error InvalidConsumer(uint64 subscriptionId, address consumer); - error InvalidSubscription(); - error OnlyCallableFromLink(); - error InvalidCalldata(); - error MustBeSubOwner(address owner); - error PendingRequestExists(); - error MustBeRequestedOwner(address proposedOwner); - error BalanceInvariantViolated(uint256 internalBalance, uint256 externalBalance); // Should never happen - event FundsRecovered(address to, uint256 amount); - - struct Subscription { - // There are only 1e9*1e18 = 1e27 juels in existence, so the balance can fit in uint96 (2^96 ~ 7e28) - uint96 balance; // Common LINK balance that is controlled by the Registry to be used for all consumer requests. - uint96 blockedBalance; // LINK balance that is reserved to pay for pending consumer requests. - } - // We use the config for the mgmt APIs - struct SubscriptionConfig { - address owner; // Owner can fund/withdraw/cancel the sub. - address requestedOwner; // For safely transferring sub ownership. - // Maintains the list of keys in s_consumers. - // We do this for 2 reasons: - // 1. To be able to clean up all keys from s_consumers when canceling a subscription. - // 2. To be able to return the list of all consumers in getSubscription. - // Note that we need the s_consumers map to be able to directly check if a - // consumer is valid without reading all the consumers from storage. - address[] consumers; - } - // Note a nonce of 0 indicates an the consumer is not assigned to that subscription. - mapping(address => mapping(uint64 => uint64)) /* consumer */ /* subscriptionId */ /* nonce */ private s_consumers; - mapping(uint64 => SubscriptionConfig) /* subscriptionId */ /* subscriptionConfig */ private s_subscriptionConfigs; - mapping(uint64 => Subscription) /* subscriptionId */ /* subscription */ private s_subscriptions; - // We make the sub count public so that its possible to - // get all the current subscriptions via getSubscription. - uint64 private s_currentsubscriptionId; - // s_totalBalance tracks the total link sent to/from - // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. - // A discrepancy with this contract's link balance indicates someone - // sent tokens using transfer and so we may need to use recoverFunds. - uint96 private s_totalBalance; - event SubscriptionCreated(uint64 indexed subscriptionId, address owner); - event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); - event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); - event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); - event SubscriptionCanceled(uint64 indexed subscriptionId, address to, uint256 amount); - event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); - event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); - - error GasLimitTooBig(uint32 have, uint32 want); - error InvalidLinkWeiPrice(int256 linkWei); - error PaymentTooLarge(); - error Reentrant(); - - mapping(address => uint96) /* oracle node */ /* LINK balance */ private s_withdrawableTokens; - struct Commitment { - uint64 subscriptionId; - address client; - uint32 gasLimit; - uint256 gasPrice; - address don; - uint96 donFee; - uint96 registryFee; - uint96 estimatedCost; - uint256 timestamp; - } - mapping(bytes32 => Commitment) /* requestID */ /* Commitment */ private s_requestCommitments; - event BillingStart(bytes32 indexed requestId, Commitment commitment); - struct ItemizedBill { - uint96 signerPayment; - uint96 transmitterPayment; - uint96 totalCost; - } - event BillingEnd( - bytes32 indexed requestId, - uint64 subscriptionId, - uint96 signerPayment, - uint96 transmitterPayment, - uint96 totalCost, - bool success - ); - event RequestTimedOut(bytes32 indexed requestId); - - struct Config { - // Maxiumum amount of gas that can be given to a request's client callback - uint32 maxGasLimit; - // Reentrancy protection. - bool reentrancyLock; - // stalenessSeconds is how long before we consider the feed price to be stale - // and fallback to fallbackWeiPerUnitLink. - uint32 stalenessSeconds; - // Gas to cover transmitter oracle payment after we calculate the payment. - // We make it configurable in case those operations are repriced. - uint256 gasAfterPaymentCalculation; - // Represents the average gas execution cost. Used in estimating cost beforehand. - uint32 gasOverhead; - // how many seconds it takes before we consider a request to be timed out - uint32 requestTimeoutSeconds; - } - int256 private s_fallbackWeiPerUnitLink; - Config private s_config; - event ConfigSet( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead - ); - - /** - * @dev Initializes the contract. - */ - function initialize(address link, address linkEthFeed, address oracle) public initializer { - __Pausable_init(); - __ConfirmedOwner_initialize(msg.sender, address(0)); - LINK = LinkTokenInterface(link); - LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); - ORACLE_WITH_ALLOWLIST = IAuthorizedOriginReceiver(oracle); - } - - /** - * @notice Sets the configuration of the Chainlink Functions billing registry - * @param maxGasLimit global max for request gas limit - * @param stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @param gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @param fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @param gasOverhead average gas execution cost used in estimating total cost - * @param requestTimeoutSeconds e2e timeout after which user won't be charged - */ - function setConfig( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead, - uint32 requestTimeoutSeconds - ) external onlyOwner { - if (fallbackWeiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); - } - s_config = Config({ - maxGasLimit: maxGasLimit, - stalenessSeconds: stalenessSeconds, - gasAfterPaymentCalculation: gasAfterPaymentCalculation, - reentrancyLock: false, - gasOverhead: gasOverhead, - requestTimeoutSeconds: requestTimeoutSeconds - }); - s_fallbackWeiPerUnitLink = fallbackWeiPerUnitLink; - emit ConfigSet(maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, gasOverhead); - } - - /** - * @notice Gets the configuration of the Chainlink Functions billing registry - * @return maxGasLimit global max for request gas limit - * @return stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @return gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @return fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @return gasOverhead average gas execution cost used in estimating total cost - * @return linkAddress address of contract for the LINK token - * @return linkPriceFeed address of contract for a conversion price between LINK token and native token - */ - function getConfig() - external - view - returns ( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead, - address linkAddress, - address linkPriceFeed - ) - { - return ( - s_config.maxGasLimit, - s_config.stalenessSeconds, - s_config.gasAfterPaymentCalculation, - s_fallbackWeiPerUnitLink, - s_config.gasOverhead, - address(LINK), - address(LINK_ETH_FEED) - ); - } - - function pause() external onlyOwner { - _pause(); - } - - function unpause() external onlyOwner { - _unpause(); - } - - function getTotalBalance() external view returns (uint256) { - return s_totalBalance; - } - - /** - * @notice Owner cancel subscription, sends remaining link directly to the subscription owner. - * @param subscriptionId subscription id - * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain - */ - function ownerCancelSubscription(uint64 subscriptionId) external onlyOwner { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - cancelSubscriptionHelper(subscriptionId, owner); - } - - /** - * @notice Recover link sent with transfer instead of transferAndCall. - * @param to address to send link to - */ - function recoverFunds(address to) external onlyOwner { - uint256 externalBalance = LINK.balanceOf(address(this)); - uint256 internalBalance = uint256(s_totalBalance); - if (internalBalance > externalBalance) { - revert BalanceInvariantViolated(internalBalance, externalBalance); - } - if (internalBalance < externalBalance) { - uint256 amount = externalBalance - internalBalance; - LINK.transfer(to, amount); - emit FundsRecovered(to, amount); - } - // If the balances are equal, nothing to be done. - } - - /** - * @inheritdoc IFunctionsBillingRegistry - */ - function getRequestConfig() external view override returns (uint32, address[] memory) { - return (s_config.maxGasLimit, getAuthorizedSenders()); - } - - /** - * @inheritdoc IFunctionsBillingRegistry - */ - function getRequiredFee( - bytes calldata /* data */, - IFunctionsBillingRegistry.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - // NOTE: Optionally, compute additional fee here - return 0; - } - - /** - * @inheritdoc IFunctionsBillingRegistry - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) public view override returns (uint96) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - uint256 executionGas = s_config.gasOverhead + s_config.gasAfterPaymentCalculation + gasLimit; - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * gasPrice * executionGas) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - return uint96(paymentNoFee + fee); - } - - /** - * @inheritdoc IFunctionsBillingRegistry - */ - function startBilling( - bytes calldata data, - RequestBilling calldata billing - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (bytes32) { - // Input validation using the subscription storage. - if (s_subscriptionConfigs[billing.subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // It's important to ensure that the consumer is in fact who they say they - // are, otherwise they could use someone else's subscription balance. - // A nonce of 0 indicates consumer is not allocated to the sub. - uint64 currentNonce = s_consumers[billing.client][billing.subscriptionId]; - if (currentNonce == 0) { - revert InvalidConsumer(billing.subscriptionId, billing.client); - } - // No lower bound on the requested gas limit. A user could request 0 - // and they would simply be billed for the gas and computation. - if (billing.gasLimit > s_config.maxGasLimit) { - revert GasLimitTooBig(billing.gasLimit, s_config.maxGasLimit); - } - - // Check that subscription can afford the estimated cost - uint96 oracleFee = IFunctionsOracle(msg.sender).getRequiredFee(data, billing); - uint96 registryFee = getRequiredFee(data, billing); - uint96 estimatedCost = estimateCost(billing.gasLimit, billing.gasPrice, oracleFee, registryFee); - uint96 effectiveBalance = s_subscriptions[billing.subscriptionId].balance - - s_subscriptions[billing.subscriptionId].blockedBalance; - if (effectiveBalance < estimatedCost) { - revert InsufficientBalance(); - } - - uint64 nonce = currentNonce + 1; - bytes32 requestId = computeRequestId(msg.sender, billing.client, billing.subscriptionId, nonce); - - Commitment memory commitment = Commitment( - billing.subscriptionId, - billing.client, - billing.gasLimit, - billing.gasPrice, - msg.sender, - oracleFee, - registryFee, - estimatedCost, - block.timestamp - ); - s_requestCommitments[requestId] = commitment; - s_subscriptions[billing.subscriptionId].blockedBalance += estimatedCost; - - emit BillingStart(requestId, commitment); - s_consumers[billing.client][billing.subscriptionId] = nonce; - return requestId; - } - - function computeRequestId( - address don, - address client, - uint64 subscriptionId, - uint64 nonce - ) private pure returns (bytes32) { - return keccak256(abi.encode(don, client, subscriptionId, nonce)); - } - - /** - * @dev calls target address with exactly gasAmount gas and data as calldata - * or reverts if at least gasAmount gas is not available. - */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly - assembly { - let g := gas() - // GAS_FOR_CALL_EXACT_CHECK = 5000 - // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow - // The gas actually passed to the callee is min(gasAmount, 63//64*gas available). - // We want to ensure that we revert if gasAmount > 63//64*gas available - // as we do not want to provide them with less, however that check itself costs - // gas. GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able - // to revert if gasAmount > 63//64*gas available. - if lt(g, 5000) { - revert(0, 0) - } - g := sub(g, 5000) - // if g - g//64 <= gasAmount, revert - // (we subtract g//64 because of EIP-150) - if iszero(gt(sub(g, div(g, 64)), gasAmount)) { - revert(0, 0) - } - // solidity calls check that a contract actually exists at the destination, so we do the same - if iszero(extcodesize(target)) { - revert(0, 0) - } - // call and return whether we succeeded. ignore return data - // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) - success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) - } - return success; - } - - /** - * @inheritdoc IFunctionsBillingRegistry - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (FulfillResult) { - Commitment memory commitment = s_requestCommitments[requestId]; - if (commitment.don == address(0)) { - return FulfillResult.INVALID_REQUEST_ID; - } - delete s_requestCommitments[requestId]; - - bytes memory callback = abi.encodeWithSelector( - IFunctionsClient.handleOracleFulfillment.selector, - requestId, - response, - err - ); - // Call with explicitly the amount of callback gas requested - // Important to not let them exhaust the gas budget and avoid payment. - // Do not allow any non-view/non-pure coordinator functions to be called - // during the consumers callback code via reentrancyLock. - // NOTE: that callWithExactGas will revert if we do not have sufficient gas - // to give the callee their requested amount. - s_config.reentrancyLock = true; - bool success = callWithExactGas(commitment.gasLimit, commitment.client, callback); - s_config.reentrancyLock = false; - - // We want to charge users exactly for how much gas they use in their callback. - // The gasAfterPaymentCalculation is meant to cover these additional operations where we - // decrement the subscription balance and increment the oracle's withdrawable balance. - ItemizedBill memory bill = calculatePaymentAmount( - initialGas, - s_config.gasAfterPaymentCalculation, - commitment.donFee, - signerCount, - commitment.registryFee, - reportValidationGas, - tx.gasprice - ); - if (s_subscriptions[commitment.subscriptionId].balance < bill.totalCost) { - revert InsufficientBalance(); - } - s_subscriptions[commitment.subscriptionId].balance -= bill.totalCost; - // Pay out signers their portion of the DON fee - for (uint256 i = 0; i < signerCount; i++) { - s_withdrawableTokens[signers[i]] += bill.signerPayment; - } - // Pay out the registry fee - s_withdrawableTokens[owner()] += commitment.registryFee; - // Reimburse the transmitter for the execution gas cost + pay them their portion of the DON fee - s_withdrawableTokens[transmitter] += bill.transmitterPayment; - // Remove blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Include payment in the event for tracking costs. - emit BillingEnd( - requestId, - commitment.subscriptionId, - bill.signerPayment, - bill.transmitterPayment, - bill.totalCost, - success - ); - return success ? FulfillResult.USER_SUCCESS : FulfillResult.USER_ERROR; - } - - // Determine the cost breakdown for payment - function calculatePaymentAmount( - uint256 startGas, - uint256 gasAfterPaymentCalculation, - uint96 donFee, - uint8 signerCount, - uint96 registryFee, - uint256 reportValidationGas, - uint256 weiPerUnitGas - ) private view returns (ItemizedBill memory) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * - weiPerUnitGas * - (reportValidationGas + gasAfterPaymentCalculation + startGas - gasleft())) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - uint96 signerPayment = donFee / uint96(signerCount); - uint96 transmitterPayment = uint96(paymentNoFee); - uint96 totalCost = SafeCast.toUint96(paymentNoFee + fee); - return ItemizedBill(signerPayment, transmitterPayment, totalCost); - } - - function getFeedData() private view returns (int256) { - uint32 stalenessSeconds = s_config.stalenessSeconds; - bool staleFallback = stalenessSeconds > 0; - (, int256 weiPerUnitLink, , uint256 timestamp, ) = LINK_ETH_FEED.latestRoundData(); - // solhint-disable-next-line not-rely-on-time - if (staleFallback && stalenessSeconds < block.timestamp - timestamp) { - weiPerUnitLink = s_fallbackWeiPerUnitLink; - } - return weiPerUnitLink; - } - - /* - * @notice Oracle withdraw LINK earned through fulfilling requests - * @notice If amount is 0 the full balance will be withdrawn - * @notice Both signing and transmitting wallets will have a balance to withdraw - * @param recipient where to send the funds - * @param amount amount to withdraw - */ - function oracleWithdraw(address recipient, uint96 amount) external nonReentrant whenNotPaused { - if (amount == 0) { - amount = s_withdrawableTokens[msg.sender]; - } - if (s_withdrawableTokens[msg.sender] < amount) { - revert InsufficientBalance(); - } - s_withdrawableTokens[msg.sender] -= amount; - s_totalBalance -= amount; - if (!LINK.transfer(recipient, amount)) { - revert InsufficientBalance(); - } - } - - function onTokenTransfer( - address /* sender */, - uint256 amount, - bytes calldata data - ) external override nonReentrant whenNotPaused { - if (msg.sender != address(LINK)) { - revert OnlyCallableFromLink(); - } - if (data.length != 32) { - revert InvalidCalldata(); - } - uint64 subscriptionId = abi.decode(data, (uint64)); - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // We do not check that the msg.sender is the subscription owner, - // anyone can fund a subscription. - uint256 oldBalance = s_subscriptions[subscriptionId].balance; - s_subscriptions[subscriptionId].balance += uint96(amount); - s_totalBalance += uint96(amount); - emit SubscriptionFunded(subscriptionId, oldBalance, oldBalance + amount); - } - - function getCurrentsubscriptionId() external view returns (uint64) { - return s_currentsubscriptionId; - } - - /** - * @notice Get details about a subscription. - * @param subscriptionId - ID of the subscription - * @return balance - LINK balance of the subscription in juels. - * @return owner - owner of the subscription. - * @return consumers - list of consumer address which are able to use this subscription. - */ - function getSubscription( - uint64 subscriptionId - ) external view returns (uint96 balance, address owner, address[] memory consumers) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return ( - s_subscriptions[subscriptionId].balance, - s_subscriptionConfigs[subscriptionId].owner, - s_subscriptionConfigs[subscriptionId].consumers - ); - } - - /** - * @notice Create a new subscription. - * @return subscriptionId - A unique subscription id. - * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - * @dev Note to fund the subscription, use transferAndCall. For example - * @dev LINKTOKEN.transferAndCall( - * @dev address(REGISTRY), - * @dev amount, - * @dev abi.encode(subscriptionId)); - */ - function createSubscription() external nonReentrant whenNotPaused onlyAuthorizedUsers returns (uint64) { - s_currentsubscriptionId++; - uint64 currentsubscriptionId = s_currentsubscriptionId; - address[] memory consumers = new address[](0); - s_subscriptions[currentsubscriptionId] = Subscription({balance: 0, blockedBalance: 0}); - s_subscriptionConfigs[currentsubscriptionId] = SubscriptionConfig({ - owner: msg.sender, - requestedOwner: address(0), - consumers: consumers - }); - - emit SubscriptionCreated(currentsubscriptionId, msg.sender); - return currentsubscriptionId; - } - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner(uint64 subscriptionId) external view override returns (address owner) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return s_subscriptionConfigs[subscriptionId].owner; - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @param newOwner - proposed new owner of the subscription - */ - function requestSubscriptionOwnerTransfer( - uint64 subscriptionId, - address newOwner - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Proposing to address(0) would never be claimable so don't need to check. - if (s_subscriptionConfigs[subscriptionId].requestedOwner != newOwner) { - s_subscriptionConfigs[subscriptionId].requestedOwner = newOwner; - emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); - } - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @dev will revert if original owner of subscriptionId has - * not requested that msg.sender become the new owner. - */ - function acceptSubscriptionOwnerTransfer( - uint64 subscriptionId - ) external nonReentrant whenNotPaused onlyAuthorizedUsers { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - if (s_subscriptionConfigs[subscriptionId].requestedOwner != msg.sender) { - revert MustBeRequestedOwner(s_subscriptionConfigs[subscriptionId].requestedOwner); - } - address oldOwner = s_subscriptionConfigs[subscriptionId].owner; - s_subscriptionConfigs[subscriptionId].owner = msg.sender; - s_subscriptionConfigs[subscriptionId].requestedOwner = address(0); - emit SubscriptionOwnerTransferred(subscriptionId, oldOwner, msg.sender); - } - - /** - * @notice Remove a consumer from a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - Consumer to remove from the subscription - */ - function removeConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (s_consumers[consumer][subscriptionId] == 0) { - revert InvalidConsumer(subscriptionId, consumer); - } - // Note bounded by MAX_CONSUMERS - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - uint256 lastConsumerIndex = consumers.length - 1; - for (uint256 i = 0; i < consumers.length; i++) { - if (consumers[i] == consumer) { - address last = consumers[lastConsumerIndex]; - // Storage write to preserve last element - s_subscriptionConfigs[subscriptionId].consumers[i] = last; - // Storage remove last element - s_subscriptionConfigs[subscriptionId].consumers.pop(); - break; - } - } - delete s_consumers[consumer][subscriptionId]; - emit SubscriptionConsumerRemoved(subscriptionId, consumer); - } - - /** - * @notice Add a consumer to a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - New consumer which can use the subscription - */ - function addConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Already maxed, cannot add any more consumers. - if (s_subscriptionConfigs[subscriptionId].consumers.length == MAX_CONSUMERS) { - revert TooManyConsumers(); - } - if (s_consumers[consumer][subscriptionId] != 0) { - // Idempotence - do nothing if already added. - // Ensures uniqueness in s_subscriptions[subscriptionId].consumers. - return; - } - // Initialize the nonce to 1, indicating the consumer is allocated. - s_consumers[consumer][subscriptionId] = 1; - s_subscriptionConfigs[subscriptionId].consumers.push(consumer); - - emit SubscriptionConsumerAdded(subscriptionId, consumer); - } - - /** - * @notice Cancel a subscription - * @param subscriptionId - ID of the subscription - * @param to - Where to send the remaining LINK to - */ - function cancelSubscription( - uint64 subscriptionId, - address to - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (pendingRequestExists(subscriptionId)) { - revert PendingRequestExists(); - } - cancelSubscriptionHelper(subscriptionId, to); - } - - function cancelSubscriptionHelper(uint64 subscriptionId, address to) private nonReentrant { - SubscriptionConfig memory subConfig = s_subscriptionConfigs[subscriptionId]; - uint96 balance = s_subscriptions[subscriptionId].balance; - // Note bounded by MAX_CONSUMERS; - // If no consumers, does nothing. - for (uint256 i = 0; i < subConfig.consumers.length; i++) { - delete s_consumers[subConfig.consumers[i]][subscriptionId]; - } - delete s_subscriptionConfigs[subscriptionId]; - delete s_subscriptions[subscriptionId]; - s_totalBalance -= balance; - if (!LINK.transfer(to, uint256(balance))) { - revert InsufficientBalance(); - } - emit SubscriptionCanceled(subscriptionId, to, balance); - } - - /** - * @notice Check to see if there exists a request commitment for all consumers for a given sub. - * @param subscriptionId - ID of the subscription - * @return true if there exists at least one unfulfilled request for the subscription, false - * otherwise. - * @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). - * @dev Used to disable subscription canceling while outstanding request are present. - */ - - function pendingRequestExists(uint64 subscriptionId) public view returns (bool) { - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - address[] memory authorizedSendersList = getAuthorizedSenders(); - for (uint256 i = 0; i < consumers.length; i++) { - for (uint256 j = 0; j < authorizedSendersList.length; j++) { - bytes32 requestId = computeRequestId( - authorizedSendersList[j], - consumers[i], - subscriptionId, - s_consumers[consumers[i]][subscriptionId] - ); - if (s_requestCommitments[requestId].don != address(0)) { - return true; - } - } - } - return false; - } - - /** - * @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled - * @param requestIdsToTimeout - A list of request IDs to time out - */ - - function timeoutRequests(bytes32[] calldata requestIdsToTimeout) external whenNotPaused { - for (uint256 i = 0; i < requestIdsToTimeout.length; i++) { - bytes32 requestId = requestIdsToTimeout[i]; - Commitment memory commitment = s_requestCommitments[requestId]; - - // Check that the message sender is the subscription owner - if (msg.sender != s_subscriptionConfigs[commitment.subscriptionId].owner) { - revert MustBeSubOwner(s_subscriptionConfigs[commitment.subscriptionId].owner); - } - - if (commitment.timestamp + s_config.requestTimeoutSeconds > block.timestamp) { - // Decrement blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Delete commitment - delete s_requestCommitments[requestId]; - emit RequestTimedOut(requestId); - } - } - } - - /** - * @dev The allow list is kept on the Oracle contract. This modifier checks if a user is authorized from there. - */ - modifier onlyAuthorizedUsers() { - if (ORACLE_WITH_ALLOWLIST.authorizedReceiverActive() && !ORACLE_WITH_ALLOWLIST.isAuthorizedSender(msg.sender)) { - revert UnauthorizedSender(); - } - _; - } - - modifier onlySubOwner(uint64 subscriptionId) { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - if (msg.sender != owner) { - revert MustBeSubOwner(owner); - } - _; - } - - modifier nonReentrant() { - if (s_config.reentrancyLock) { - revert Reentrant(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override onlyOwner returns (bool) { - return true; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsClient.sol deleted file mode 100644 index 355d50f8e3c..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsClient.sol +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {Functions} from "./Functions.sol"; -import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; -import {IFunctionsOracle} from "./interfaces/IFunctionsOracle.sol"; - -/** - * @title The Chainlink Functions client contract - * @notice Contract writers can inherit this contract in order to create Chainlink Functions requests - */ -abstract contract FunctionsClient is IFunctionsClient { - IFunctionsOracle internal s_oracle; - mapping(bytes32 => address) internal s_pendingRequests; - - event RequestSent(bytes32 indexed id); - event RequestFulfilled(bytes32 indexed id); - - error SenderIsNotRegistry(); - error RequestIsAlreadyPending(); - error RequestIsNotPending(); - - constructor(address oracle) { - setOracle(oracle); - } - - /** - * @inheritdoc IFunctionsClient - */ - function getDONPublicKey() external view override returns (bytes memory) { - return s_oracle.getDONPublicKey(); - } - - /** - * @notice Estimate the total cost that will be charged to a subscription to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param req The initialized Functions.Request - * @param subscriptionId The subscription ID - * @param gasLimit gas limit for the fulfillment callback - * @return billedCost Cost in Juels (1e18) of LINK - */ - function estimateCost( - Functions.Request memory req, - uint64 subscriptionId, - uint32 gasLimit, - uint256 gasPrice - ) public view returns (uint96) { - return s_oracle.estimateCost(subscriptionId, Functions.encodeCBOR(req), gasLimit, gasPrice); - } - - /** - * @notice Sends a Chainlink Functions request to the stored oracle address - * @param req The initialized Functions.Request - * @param subscriptionId The subscription ID - * @param gasLimit gas limit for the fulfillment callback - * @return requestId The generated request ID - */ - function sendRequest( - Functions.Request memory req, - uint64 subscriptionId, - uint32 gasLimit - ) internal returns (bytes32) { - bytes32 requestId = s_oracle.sendRequest(subscriptionId, Functions.encodeCBOR(req), gasLimit); - s_pendingRequests[requestId] = s_oracle.getRegistry(); - emit RequestSent(requestId); - return requestId; - } - - /** - * @notice User defined function to handle a response - * @param requestId The request ID, returned by sendRequest() - * @param response Aggregated response from the user code - * @param err Aggregated error from the user code or from the execution pipeline - * Either response or error parameter will be set, but never both - */ - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; - - /** - * @inheritdoc IFunctionsClient - */ - function handleOracleFulfillment( - bytes32 requestId, - bytes memory response, - bytes memory err - ) external override recordChainlinkFulfillment(requestId) { - fulfillRequest(requestId, response, err); - } - - /** - * @notice Sets the stored Oracle address - * @param oracle The address of Functions Oracle contract - */ - function setOracle(address oracle) internal { - s_oracle = IFunctionsOracle(oracle); - } - - /** - * @notice Gets the stored address of the oracle contract - * @return The address of the oracle contract - */ - function getChainlinkOracleAddress() internal view returns (address) { - return address(s_oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param oracleAddress The address of the oracle contract that will fulfill the request - * @param requestId The request ID used for the response - */ - function addExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { - s_pendingRequests[requestId] = oracleAddress; - } - - /** - * @dev Reverts if the sender is not the oracle that serviced the request. - * Emits RequestFulfilled event. - * @param requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 requestId) { - if (msg.sender != s_pendingRequests[requestId]) { - revert SenderIsNotRegistry(); - } - delete s_pendingRequests[requestId]; - emit RequestFulfilled(requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 requestId) { - if (s_pendingRequests[requestId] != address(0)) { - revert RequestIsAlreadyPending(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsOracle.sol b/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsOracle.sol deleted file mode 100644 index b1233eeb526..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/FunctionsOracle.sol +++ /dev/null @@ -1,292 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {IFunctionsOracle, IFunctionsBillingRegistry} from "./interfaces/IFunctionsOracle.sol"; -import {OCR2BaseUpgradeable} from "./ocr/OCR2BaseUpgradeable.sol"; -import {AuthorizedOriginReceiverUpgradeable} from "./accessControl/AuthorizedOriginReceiverUpgradeable.sol"; -import {Initializable} from "../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Oracle contract - * @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsOracle is Initializable, IFunctionsOracle, OCR2BaseUpgradeable, AuthorizedOriginReceiverUpgradeable { - event OracleRequest( - bytes32 indexed requestId, - address requestingContract, - address requestInitiator, - uint64 subscriptionId, - address subscriptionOwner, - bytes data - ); - event OracleResponse(bytes32 indexed requestId); - event UserCallbackError(bytes32 indexed requestId, string reason); - event UserCallbackRawError(bytes32 indexed requestId, bytes lowLevelData); - event InvalidRequestID(bytes32 indexed requestId); - event ResponseTransmitted(bytes32 indexed requestId, address transmitter); - - error EmptyRequestData(); - error InconsistentReportData(); - error EmptyPublicKey(); - error EmptyBillingRegistry(); - error UnauthorizedPublicKeyChange(); - - bytes private s_donPublicKey; - IFunctionsBillingRegistry private s_registry; - mapping(address => bytes) private s_nodePublicKeys; - - bytes private s_thresholdPublicKey; - - /** - * @dev Initializes the contract. - */ - function initialize() public initializer { - __OCR2Base_initialize(true); - __AuthorizedOriginReceiver_initialize(true); - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure override returns (string memory) { - return "FunctionsOracle 0.0.0"; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function getRegistry() external view override returns (address) { - return address(s_registry); - } - - /** - * @inheritdoc IFunctionsOracle - */ - function setRegistry(address registryAddress) external override onlyOwner { - if (registryAddress == address(0)) { - revert EmptyBillingRegistry(); - } - s_registry = IFunctionsBillingRegistry(registryAddress); - } - - /** - * @inheritdoc IFunctionsOracle - */ - function getThresholdPublicKey() external view override returns (bytes memory) { - return s_thresholdPublicKey; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { - if (thresholdPublicKey.length == 0) { - revert EmptyPublicKey(); - } - s_thresholdPublicKey = thresholdPublicKey; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function getDONPublicKey() external view override returns (bytes memory) { - return s_donPublicKey; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { - if (donPublicKey.length == 0) { - revert EmptyPublicKey(); - } - s_donPublicKey = donPublicKey; - } - - /** - * @dev check if node is in current transmitter list - */ - function _isTransmitter(address node) internal view returns (bool) { - address[] memory nodes = this.transmitters(); - for (uint256 i = 0; i < nodes.length; i++) { - if (nodes[i] == node) { - return true; - } - } - return false; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function setNodePublicKey(address node, bytes calldata publicKey) external override { - // Owner can set anything. Transmitters can set only their own key. - if (!(msg.sender == owner() || (_isTransmitter(msg.sender) && msg.sender == node))) { - revert UnauthorizedPublicKeyChange(); - } - s_nodePublicKeys[node] = publicKey; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function deleteNodePublicKey(address node) external override { - // Owner can delete anything. Others can delete only their own key. - if (!(msg.sender == owner() || msg.sender == node)) { - revert UnauthorizedPublicKeyChange(); - } - delete s_nodePublicKeys[node]; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function getAllNodePublicKeys() external view override returns (address[] memory, bytes[] memory) { - address[] memory nodes = this.transmitters(); - bytes[] memory keys = new bytes[](nodes.length); - for (uint256 i = 0; i < nodes.length; i++) { - keys[i] = s_nodePublicKeys[nodes[i]]; - } - return (nodes, keys); - } - - /** - * @inheritdoc IFunctionsOracle - */ - function getRequiredFee( - bytes calldata /* data */, - IFunctionsBillingRegistry.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - // NOTE: Optionally, compute additional fee split between nodes of the DON here - // e.g. 0.1 LINK * s_transmitters.length - return 0; - } - - /** - * @inheritdoc IFunctionsOracle - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view override registryIsSet returns (uint96) { - IFunctionsBillingRegistry.RequestBilling memory billing = IFunctionsBillingRegistry.RequestBilling( - subscriptionId, - msg.sender, - gasLimit, - gasPrice - ); - uint96 donFee = getRequiredFee(data, billing); - uint96 registryFee = s_registry.getRequiredFee(data, billing); - return s_registry.estimateCost(gasLimit, gasPrice, donFee, registryFee); - } - - /** - * @inheritdoc IFunctionsOracle - */ - function sendRequest( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit - ) external override registryIsSet validateAuthorizedSender returns (bytes32) { - if (data.length == 0) { - revert EmptyRequestData(); - } - bytes32 requestId = s_registry.startBilling( - data, - IFunctionsBillingRegistry.RequestBilling(subscriptionId, msg.sender, gasLimit, tx.gasprice) - ); - emit OracleRequest( - requestId, - msg.sender, - tx.origin, - subscriptionId, - s_registry.getSubscriptionOwner(subscriptionId), - data - ); - return requestId; - } - - function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _validateReport( - bytes32 /* configDigest */, - uint40 /* epochAndRound */, - bytes memory /* report */ - ) internal pure override returns (bool) { - // validate within _report to save gas - return true; - } - - function _report( - uint256 initialGas, - address transmitter, - uint8 signerCount, - address[maxNumOracles] memory signers, - bytes calldata report - ) internal override registryIsSet { - bytes32[] memory requestIds; - bytes[] memory results; - bytes[] memory errors; - (requestIds, results, errors) = abi.decode(report, (bytes32[], bytes[], bytes[])); - if (requestIds.length == 0 || requestIds.length != results.length || requestIds.length != errors.length) { - revert ReportInvalid(); - } - - uint256 reportValidationGasShare = (initialGas - gasleft()) / requestIds.length; - - for (uint256 i = 0; i < requestIds.length; i++) { - try - s_registry.fulfillAndBill( - requestIds[i], - results[i], - errors[i], - transmitter, - signers, - signerCount, - reportValidationGasShare, - gasleft() - ) - returns (IFunctionsBillingRegistry.FulfillResult result) { - if (result == IFunctionsBillingRegistry.FulfillResult.USER_SUCCESS) { - emit OracleResponse(requestIds[i]); - emit ResponseTransmitted(requestIds[i], transmitter); - } else if (result == IFunctionsBillingRegistry.FulfillResult.USER_ERROR) { - emit UserCallbackError(requestIds[i], "error in callback"); - emit ResponseTransmitted(requestIds[i], transmitter); - } else if (result == IFunctionsBillingRegistry.FulfillResult.INVALID_REQUEST_ID) { - emit InvalidRequestID(requestIds[i]); - } - } catch (bytes memory reason) { - emit UserCallbackRawError(requestIds[i], reason); - emit ResponseTransmitted(requestIds[i], transmitter); - } - } - } - - /** - * @dev Reverts if the the billing registry is not set - */ - modifier registryIsSet() { - if (address(s_registry) == address(0)) { - revert EmptyBillingRegistry(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override returns (bool) { - return msg.sender == owner(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[48] private __gap; -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiver.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiver.sol deleted file mode 100644 index 16918072fba..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiver.sol +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {IAuthorizedOriginReceiver} from "./interfaces/IAuthorizedOriginReceiver.sol"; - -/** - * @notice Modified AuthorizedReciever abstract for use on the FunctionsOracle contract to limit usage - * @notice Uses tx.origin instead of msg.sender because the client contract sends messages to the Oracle contract - */ - -abstract contract AuthorizedOriginReceiver is IAuthorizedOriginReceiver { - using EnumerableSet for EnumerableSet.AddressSet; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - event AuthorizedSendersActive(address account); - event AuthorizedSendersDeactive(address account); - - error EmptySendersList(); - error UnauthorizedSender(); - error NotAllowedToSetSenders(); - error AlreadySet(); - - bool private s_active; - EnumerableSet.AddressSet private s_authorizedSenders; - - /** - * @dev Initializes the contract in active state. - */ - constructor() { - s_active = true; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function authorizedReceiverActive() public view virtual override returns (bool) { - return s_active; - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to block unuthorized senders. - * - * Requirements: - * - * - The contract must not be deactive. - */ - function activateAuthorizedReceiver() external override validateAuthorizedSenderSetter { - if (authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = true; - emit AuthorizedSendersActive(msg.sender); - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to allow all senders. - * - * Requirements: - * - * - The contract must be active. - */ - function deactivateAuthorizedReceiver() external override validateAuthorizedSenderSetter { - if (!authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = false; - emit AuthorizedSendersDeactive(msg.sender); - } - - /** - * @notice Sets the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to grant access - */ - function addAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.add(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Remove the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to revoke access - */ - function removeAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.remove(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() public view override returns (address[] memory) { - return EnumerableSet.values(s_authorizedSenders); - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view override returns (bool) { - if (!authorizedReceiverActive()) { - return true; - } - return s_authorizedSenders.contains(sender); - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - if (!isAuthorizedSender(tx.origin)) { - revert UnauthorizedSender(); - } - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - if (!_canSetAuthorizedSenders()) { - revert NotAllowedToSetSenders(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiverUpgradeable.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiverUpgradeable.sol deleted file mode 100644 index 762bcb67b9f..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedOriginReceiverUpgradeable.sol +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {Initializable} from "../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; -import {IAuthorizedOriginReceiver} from "./interfaces/IAuthorizedOriginReceiver.sol"; - -/** - * @notice Modified AuthorizedReciever abstract for use on the FunctionsOracle contract to limit usage - * @notice Uses tx.origin instead of msg.sender because the client contract sends messages to the Oracle contract - */ - -abstract contract AuthorizedOriginReceiverUpgradeable is Initializable, IAuthorizedOriginReceiver { - using EnumerableSet for EnumerableSet.AddressSet; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - event AuthorizedSendersActive(address account); - event AuthorizedSendersDeactive(address account); - - error EmptySendersList(); - error UnauthorizedSender(); - error NotAllowedToSetSenders(); - error AlreadySet(); - - bool private s_active; - EnumerableSet.AddressSet private s_authorizedSenders; - address[] private s_authorizedSendersList; // DEPRECATED, TODO: remove on proxy re-deploy - - /** - * @dev Initializes the contract in active state. - */ - function __AuthorizedOriginReceiver_initialize(bool active) internal onlyInitializing { - s_active = active; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function authorizedReceiverActive() public view virtual override returns (bool) { - return s_active; - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to block unuthorized senders. - * - * Requirements: - * - * - The contract must not be deactive. - */ - function activateAuthorizedReceiver() external override validateAuthorizedSenderSetter { - if (authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = true; - emit AuthorizedSendersActive(msg.sender); - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to allow all senders. - * - * Requirements: - * - * - The contract must be active. - */ - function deactivateAuthorizedReceiver() external override validateAuthorizedSenderSetter { - if (!authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = false; - emit AuthorizedSendersDeactive(msg.sender); - } - - /** - * @notice Sets the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to grant access - */ - function addAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.add(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Remove the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to revoke access - */ - function removeAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.remove(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() public view override returns (address[] memory) { - return EnumerableSet.values(s_authorizedSenders); - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view override returns (bool) { - if (!authorizedReceiverActive()) { - return true; - } - return s_authorizedSenders.contains(sender); - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - if (!isAuthorizedSender(tx.origin)) { - revert UnauthorizedSender(); - } - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - if (!_canSetAuthorizedSenders()) { - revert NotAllowedToSetSenders(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedReceiver.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedReceiver.sol deleted file mode 100644 index 92d8af6891d..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/AuthorizedReceiver.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {EnumerableSet} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {IAuthorizedReceiver} from "./interfaces/IAuthorizedReceiver.sol"; - -abstract contract AuthorizedReceiver is IAuthorizedReceiver { - using EnumerableSet for EnumerableSet.AddressSet; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - - error EmptySendersList(); - error UnauthorizedSender(); - error NotAllowedToSetSenders(); - - EnumerableSet.AddressSet private s_authorizedSenders; - address[] private s_authorizedSendersList; - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param senders The addresses of the authorized Chainlink node - */ - function setAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < s_authorizedSendersList.length; i++) { - s_authorizedSenders.remove(s_authorizedSendersList[i]); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.add(senders[i]); - } - s_authorizedSendersList = senders; - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() public view override returns (address[] memory) { - return s_authorizedSendersList; - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view override returns (bool) { - return s_authorizedSenders.contains(sender); - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - if (!isAuthorizedSender(msg.sender)) { - revert UnauthorizedSender(); - } - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - if (!_canSetAuthorizedSenders()) { - revert NotAllowedToSetSenders(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/ConfirmedOwnerUpgradeable.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/ConfirmedOwnerUpgradeable.sol deleted file mode 100644 index 284c5637167..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/ConfirmedOwnerUpgradeable.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {IOwnable} from "../../../../shared/interfaces/IOwnable.sol"; -import {Initializable} from "../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title The ConfirmedOwnerUpgradeable contract - * @notice An upgrade compatible contract with helpers for basic contract ownership. - */ -contract ConfirmedOwnerUpgradeable is Initializable, IOwnable { - address private s_owner; - address private s_pendingOwner; - - event OwnershipTransferRequested(address indexed from, address indexed to); - event OwnershipTransferred(address indexed from, address indexed to); - - error OwnerMustBeSet(); - error NotProposedOwner(); - error CannotSelfTransfer(); - error OnlyCallableByOwner(); - - /** - * @dev Initializes the contract in unpaused state. - */ - function __ConfirmedOwner_initialize(address newOwner, address pendingOwner) internal onlyInitializing { - if (newOwner == address(0)) { - revert OwnerMustBeSet(); - } - - s_owner = newOwner; - if (pendingOwner != address(0)) { - _transferOwnership(pendingOwner); - } - } - - /** - * @notice Allows an owner to begin transferring ownership to a new address, - * pending. - */ - function transferOwnership(address to) public override onlyOwner { - _transferOwnership(to); - } - - /** - * @notice Allows an ownership transfer to be completed by the recipient. - */ - function acceptOwnership() external override { - if (msg.sender != s_pendingOwner) { - revert NotProposedOwner(); - } - - address oldOwner = s_owner; - s_owner = msg.sender; - s_pendingOwner = address(0); - - emit OwnershipTransferred(oldOwner, msg.sender); - } - - /** - * @notice Get the current owner - */ - function owner() public view override returns (address) { - return s_owner; - } - - /** - * @notice validate, transfer ownership, and emit relevant events - */ - function _transferOwnership(address to) private { - if (to == msg.sender) { - revert CannotSelfTransfer(); - } - - s_pendingOwner = to; - - emit OwnershipTransferRequested(s_owner, to); - } - - /** - * @notice validate access - */ - function _validateOwnership() internal view { - if (msg.sender != s_owner) { - revert OnlyCallableByOwner(); - } - } - - /** - * @notice Reverts if called by anyone other than the contract owner. - */ - modifier onlyOwner() { - _validateOwnership(); - _; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedOriginReceiver.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedOriginReceiver.sol deleted file mode 100644 index dd3dbb71430..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedOriginReceiver.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @notice Modified AuthorizedReciever abstract for use on the Functions Oracle contract to limit usage - * @notice Uses tx.origin instead of msg.sender because the client contract sends messages to the Oracle contract - */ - -interface IAuthorizedOriginReceiver { - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function authorizedReceiverActive() external view returns (bool); - - /** - * @dev Triggers AuthorizedOriginReceiver usage to block unuthorized senders. - * - * Requirements: - * - * - The contract must not be deactive. - */ - function activateAuthorizedReceiver() external; - - /** - * @dev Triggers AuthorizedOriginReceiver usage to allow all senders. - * - * Requirements: - * - * - The contract must be active. - */ - function deactivateAuthorizedReceiver() external; - - /** - * @notice Sets the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to grant access - */ - function addAuthorizedSenders(address[] calldata senders) external; - - /** - * @notice Remove the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to revoke access - */ - function removeAuthorizedSenders(address[] calldata senders) external; - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() external view returns (address[] memory); - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) external view returns (bool); -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedReceiver.sol b/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedReceiver.sol deleted file mode 100644 index 78140d58682..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/accessControl/interfaces/IAuthorizedReceiver.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IAuthorizedReceiver { - function isAuthorizedSender(address sender) external view returns (bool); - - function getAuthorizedSenders() external returns (address[] memory); - - function setAuthorizedSenders(address[] calldata senders) external; -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/example/FunctionsClientExample.sol b/contracts/src/v0.8/functions/dev/v0_0_0/example/FunctionsClientExample.sol deleted file mode 100644 index 2d118c6961a..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/example/FunctionsClientExample.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsClient} from "../FunctionsClient.sol"; -import {Functions} from "../Functions.sol"; -import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; - -/** - * @title Chainlink Functions example client contract implementation - */ -contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { - using Functions for Functions.Request; - - uint32 public constant MAX_CALLBACK_GAS = 70_000; - - bytes32 public lastRequestId; - bytes32 public lastResponse; - bytes32 public lastError; - uint32 public lastResponseLength; - uint32 public lastErrorLength; - - error UnexpectedRequestID(bytes32 requestId); - - constructor(address oracle) FunctionsClient(oracle) ConfirmedOwner(msg.sender) {} - - /** - * @notice Send a simple request - * @param source JavaScript source code - * @param secrets Encrypted secrets payload - * @param args List of arguments accessible from within the source code - * @param subscriptionId Billing ID - */ - function SendRequest( - string calldata source, - bytes calldata secrets, - string[] calldata args, - uint64 subscriptionId - ) external onlyOwner { - Functions.Request memory req; - req.initializeRequestForInlineJavaScript(source); - if (secrets.length > 0) req.addRemoteSecrets(secrets); - if (args.length > 0) req.addArgs(args); - lastRequestId = sendRequest(req, subscriptionId, MAX_CALLBACK_GAS); - } - - /** - * @notice Store latest result/error - * @param requestId The request ID, returned by sendRequest() - * @param response Aggregated response from the user code - * @param err Aggregated error from the user code or from the execution pipeline - * Either response or error parameter will be set, but never both - */ - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { - if (lastRequestId != requestId) { - revert UnexpectedRequestID(requestId); - } - // Save only the first 32 bytes of reponse/error to always fit within MAX_CALLBACK_GAS - lastResponse = bytesToBytes32(response); - lastResponseLength = uint32(response.length); - lastError = bytesToBytes32(err); - lastErrorLength = uint32(err.length); - } - - function bytesToBytes32(bytes memory b) private pure returns (bytes32) { - bytes32 out; - uint256 maxLen = 32; - if (b.length < 32) { - maxLen = b.length; - } - for (uint256 i = 0; i < maxLen; i++) { - out |= bytes32(b[i]) >> (i * 8); - } - return out; - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsBillingRegistry.sol b/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsBillingRegistry.sol deleted file mode 100644 index 01a7f72ecbe..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsBillingRegistry.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions billing subscription registry interface. - */ -interface IFunctionsBillingRegistry { - struct RequestBilling { - // a unique subscription ID allocated by billing system, - uint64 subscriptionId; - // the client contract that initiated the request to the DON - // to use the subscription it must be added as a consumer on the subscription - address client; - // customer specified gas limit for the fulfillment callback - uint32 gasLimit; - // the expected gas price used to execute the transaction - uint256 gasPrice; - } - - enum FulfillResult { - USER_SUCCESS, - USER_ERROR, - INVALID_REQUEST_ID - } - - /** - * @notice Get configuration relevant for making requests - * @return uint32 global max for request gas limit - * @return address[] list of registered DONs - */ - function getRequestConfig() external view returns (uint32, address[] memory); - - /** - * @notice Determine the charged fee that will be paid to the Registry owner - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee(bytes calldata data, RequestBilling memory billing) external view returns (uint96); - - /** - * @notice Estimate the total cost to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param gasLimit Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasPrice The request's billing configuration - * @param donFee Fee charged by the DON that is paid to Oracle Node - * @param registryFee Fee charged by the DON that is paid to Oracle Node - * @return costEstimate Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) external view returns (uint96); - - /** - * @notice Initiate the billing process for an Functions request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing Billing configuration for the request - * @return requestId - A unique identifier of the request. Can be used to match a request to a response in fulfillRequest. - * @dev Only callable by a node that has been approved on the Registry - */ - function startBilling(bytes calldata data, RequestBilling calldata billing) external returns (bytes32); - - /** - * @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription - * @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment - * @param response response data from DON consensus - * @param err error from DON consensus - * @param transmitter the Oracle who sent the report - * @param signers the Oracles who had a part in generating the report - * @param signerCount the number of signers on the report - * @param reportValidationGas the amount of gas used for the report validation. Cost is split by all fulfillments on the report. - * @param initialGas the initial amount of gas that should be used as a baseline to charge the single fulfillment for execution cost - * @return result fulfillment result - * @dev Only callable by a node that has been approved on the Registry - * @dev simulated offchain to determine if sufficient balance is present to fulfill the request - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, // 31 comes from OCR2Abstract.sol's maxNumOracles constant - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external returns (FulfillResult); - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner(uint64 subscriptionId) external view returns (address owner); -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsClient.sol b/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsClient.sol deleted file mode 100644 index bf7b74c2209..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsClient.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions client interface. - */ -interface IFunctionsClient { - /** - * @notice Returns the DON's secp256k1 public key used to encrypt secrets - * @dev All Oracles nodes have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Chainlink Functions response handler called by the designated transmitter node in an OCR round. - * @param requestId The requestId returned by FunctionsClient.sendRequest(). - * @param response Aggregated response from the user code. - * @param err Aggregated error either from the user code or from the execution pipeline. - * Either response or error parameter will be set, but never both. - */ - function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsOracle.sol b/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsOracle.sol deleted file mode 100644 index 52f8023b7b9..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/interfaces/IFunctionsOracle.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {IFunctionsBillingRegistry} from "./IFunctionsBillingRegistry.sol"; - -/** - * @title Chainlink Functions oracle interface. - */ -interface IFunctionsOracle { - /** - * @notice Gets the stored billing registry address - * @return registryAddress The address of Chainlink Functions billing registry contract - */ - function getRegistry() external view returns (address); - - /** - * @notice Sets the stored billing registry address - * @param registryAddress The new address of Chainlink Functions billing registry contract - */ - function setRegistry(address registryAddress) external; - - /** - * @notice Returns the DON's threshold encryption public key used to encrypt secrets - * @dev All nodes on the DON have separate key shares of the threshold decryption key - * and nodes must participate in a threshold decryption OCR round to decrypt secrets - * @return thresholdPublicKey the DON's threshold encryption public key - */ - function getThresholdPublicKey() external view returns (bytes memory); - - /** - * @notice Sets the DON's threshold encryption public key used to encrypt secrets - * @dev Used to rotate the key - * @param thresholdPublicKey The new public key - */ - function setThresholdPublicKey(bytes calldata thresholdPublicKey) external; - - /** - * @notice Returns the DON's secp256k1 public key that is used to encrypt secrets - * @dev All nodes on the DON have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey the DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Sets DON's secp256k1 public key used to encrypt secrets - * @dev Used to rotate the key - * @param donPublicKey The new public key - */ - function setDONPublicKey(bytes calldata donPublicKey) external; - - /** - * @notice Sets a per-node secp256k1 public key used to encrypt secrets for that node - * @dev Callable only by contract owner and DON members - * @param node node's address - * @param publicKey node's public key - */ - function setNodePublicKey(address node, bytes calldata publicKey) external; - - /** - * @notice Deletes node's public key - * @dev Callable only by contract owner or the node itself - * @param node node's address - */ - function deleteNodePublicKey(address node) external; - - /** - * @notice Return two arrays of equal size containing DON members' addresses and their corresponding - * public keys (or empty byte arrays if per-node key is not defined) - */ - function getAllNodePublicKeys() external view returns (address[] memory, bytes[] memory); - - /** - * @notice Determine the fee charged by the DON that will be split between signing Node Operators for servicing the request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee( - bytes calldata data, - IFunctionsBillingRegistry.RequestBilling calldata billing - ) external view returns (uint96); - - /** - * @notice Estimate the total cost that will be charged to a subscription to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return billedCost Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view returns (uint96); - - /** - * @notice Sends a request (encoded as data) using the provided subscriptionId - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return requestId A unique request identifier (unique per DON) - */ - function sendRequest(uint64 subscriptionId, bytes calldata data, uint32 gasLimit) external returns (bytes32); -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2BaseUpgradeable.sol b/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2BaseUpgradeable.sol deleted file mode 100644 index 25481ceb73e..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2BaseUpgradeable.sol +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {ConfirmedOwnerUpgradeable} from "../accessControl/ConfirmedOwnerUpgradeable.sol"; -import {OCR2Abstract} from "./OCR2Abstract.sol"; -import {Initializable} from "../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @notice Onchain verification of reports from the offchain reporting protocol - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - * @dev For details on its operation, see the offchain reporting protocol design - * doc, which refers to this contract as simply the "contract". - * @dev This contract is meant to aid rapid development of new applications based on OCR2. - * However, for actual production contracts, it is expected that most of the logic of this contract - * will be folded directly into the application contract. Inheritance prevents us from doing lots - * of juicy storage layout optimizations, leading to a substantial increase in gas cost. - */ -abstract contract OCR2BaseUpgradeable is Initializable, ConfirmedOwnerUpgradeable, OCR2Abstract { - error ReportInvalid(); - - bool internal i_uniqueReports; - - /** - * @dev Initializes the contract. - */ - function __OCR2Base_initialize(bool uniqueReports) internal onlyInitializing { - __ConfirmedOwner_initialize(msg.sender, address(0)); - i_uniqueReports = uniqueReports; - } - - uint256 private constant maxUint32 = (1 << 32) - 1; - - // Storing these fields used on the hot path in a ConfigInfo variable reduces the - // retrieval of all of them to a single SLOAD. If any further fields are - // added, make sure that storage of the struct still takes at most 32 bytes. - struct ConfigInfo { - bytes32 latestConfigDigest; - uint8 f; // TODO: could be optimized by squeezing into one slot - uint8 n; - } - ConfigInfo internal s_configInfo; - - // incremented each time a new config is posted. This count is incorporated - // into the config digest, to prevent replay attacks. - uint32 internal s_configCount; - uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems - // to extract config from logs. - - // Used for s_oracles[a].role, where a is an address, to track the purpose - // of the address, or to indicate that the address is unset. - enum Role { - // No oracle role has been set for address a - Unset, - // Signing address for the s_oracles[a].index'th oracle. I.e., report - // signatures from this oracle should ecrecover back to address a. - Signer, - // Transmission address for the s_oracles[a].index'th oracle. I.e., if a - // report is received by OCR2Aggregator.transmit in which msg.sender is - // a, it is attributed to the s_oracles[a].index'th oracle. - Transmitter - } - - struct Oracle { - uint8 index; // Index of oracle in s_signers/s_transmitters - Role role; // Role of the address which mapped to this struct - } - - mapping(address => Oracle) /* signer OR transmitter address */ internal s_oracles; - - // s_signers contains the signing address of each oracle - address[] internal s_signers; - - // s_transmitters contains the transmission address of each oracle, - // i.e. the address the oracle actually sends transactions to the contract from - address[] internal s_transmitters; - - /* - * Config logic - */ - - // Reverts transaction if config args are invalid - modifier checkConfigValid( - uint256 _numSigners, - uint256 _numTransmitters, - uint256 _f - ) { - require(_numSigners <= maxNumOracles, "too many signers"); - require(_f > 0, "f must be positive"); - require(_numSigners == _numTransmitters, "oracle addresses out of registration"); - require(_numSigners > 3 * _f, "faulty-oracle f too high"); - _; - } - - struct SetConfigArgs { - address[] signers; - address[] transmitters; - uint8 f; - bytes onchainConfig; - uint64 offchainConfigVersion; - bytes offchainConfig; - } - - /// @inheritdoc OCR2Abstract - function latestConfigDigestAndEpoch() - external - view - virtual - override - returns (bool scanLogs, bytes32 configDigest, uint32 epoch) - { - return (true, bytes32(0), uint32(0)); - } - - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param _signers addresses with which oracles sign the reports - * @param _transmitters addresses oracles use to transmit the reports - * @param _f number of faulty oracles the system can tolerate - * @param _onchainConfig encoded on-chain contract configuration - * @param _offchainConfigVersion version number for offchainEncoding schema - * @param _offchainConfig encoded off-chain oracle configuration - */ - function setConfig( - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _offchainConfigVersion, - bytes memory _offchainConfig - ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner { - SetConfigArgs memory args = SetConfigArgs({ - signers: _signers, - transmitters: _transmitters, - f: _f, - onchainConfig: _onchainConfig, - offchainConfigVersion: _offchainConfigVersion, - offchainConfig: _offchainConfig - }); - - _beforeSetConfig(args.f, args.onchainConfig); - - while (s_signers.length != 0) { - // remove any old signer/transmitter addresses - uint256 lastIdx = s_signers.length - 1; - address signer = s_signers[lastIdx]; - address transmitter = s_transmitters[lastIdx]; - delete s_oracles[signer]; - delete s_oracles[transmitter]; - s_signers.pop(); - s_transmitters.pop(); - } - - for (uint256 i = 0; i < args.signers.length; ++i) { - // add new signer/transmitter addresses - require(s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address"); - s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); - require(s_oracles[args.transmitters[i]].role == Role.Unset, "repeated transmitter address"); - s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); - s_signers.push(args.signers[i]); - s_transmitters.push(args.transmitters[i]); - } - s_configInfo.f = args.f; - uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; - s_latestConfigBlockNumber = uint32(block.number); - s_configCount += 1; - { - s_configInfo.latestConfigDigest = configDigestFromConfigData( - block.chainid, - address(this), - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - } - s_configInfo.n = uint8(args.signers.length); - - emit ConfigSet( - previousConfigBlockNumber, - s_configInfo.latestConfigDigest, - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - - _afterSetConfig(args.f, args.onchainConfig); - } - - function configDigestFromConfigData( - uint256 _chainId, - address _contractAddress, - uint64 _configCount, - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _encodedConfigVersion, - bytes memory _encodedConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - _chainId, - _contractAddress, - _configCount, - _signers, - _transmitters, - _f, - _onchainConfig, - _encodedConfigVersion, - _encodedConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see configDigestFromConfigData) - */ - function latestConfigDetails() - external - view - override - returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) - { - return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); - } - - /** - * @return list of addresses permitted to transmit reports to this contract - * @dev The list will match the order used to specify the transmitter during setConfig - */ - function transmitters() external view returns (address[] memory) { - return s_transmitters; - } - - function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - - /** - * @dev hook to allow additional validation of the report by the extending contract - * @param configDigest separation tag for current config (see configDigestFromConfigData) - * @param epochAndRound 27 byte padding, 4-byte epoch and 1-byte round - * @param report serialized report - */ - function _validateReport( - bytes32 configDigest, - uint40 epochAndRound, - bytes memory report - ) internal virtual returns (bool); - - /** - * @dev hook called after the report has been fully validated - * for the extending contract to handle additional logic, such as oracle payment - * @param initialGas the amount of gas before validation - * @param transmitter the address of the account that submitted the report - * @param signers the addresses of all signing accounts - * @param report serialized report - */ - function _report( - uint256 initialGas, - address transmitter, - uint8 signerCount, - address[maxNumOracles] memory signers, - bytes calldata report - ) internal virtual; - - // The constant-length components of the msg.data sent to transmit. - // See the "If we wanted to call sam" example on for example reasoning - // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html - uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = - 4 + // function selector - 32 * - 3 + // 3 words containing reportContext - 32 + // word containing start location of abiencoded report value - 32 + // word containing location start of abiencoded rs value - 32 + // word containing start location of abiencoded ss value - 32 + // rawVs value - 32 + // word containing length of report - 32 + // word containing length rs - 32 + // word containing length of ss - 0; // placeholder - - function requireExpectedMsgDataLength( - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss - ) private pure { - // calldata will never be big enough to make this overflow - uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + - report.length + // one byte pure entry in _report - rs.length * - 32 + // 32 bytes per entry in _rs - ss.length * - 32 + // 32 bytes per entry in _ss - 0; // placeholder - require(msg.data.length == expected, "calldata length mismatch"); - } - - /** - * @notice transmit is called to post a new report to the contract - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ - function transmit( - // NOTE: If these parameters are changed, expectedMsgDataLength and/or - // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly - bytes32[3] calldata reportContext, - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss, - bytes32 rawVs // signatures - ) external override { - uint256 initialGas = gasleft(); // This line must come first - - { - // reportContext consists of: - // reportContext[0]: ConfigDigest - // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round - // reportContext[2]: ExtraHash - bytes32 configDigest = reportContext[0]; - uint32 epochAndRound = uint32(uint256(reportContext[1])); - - if (!_validateReport(configDigest, epochAndRound, report)) { - revert ReportInvalid(); - } - - emit Transmitted(configDigest, uint32(epochAndRound >> 8)); - - ConfigInfo memory configInfo = s_configInfo; - require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); - - requireExpectedMsgDataLength(report, rs, ss); - - uint256 expectedNumSignatures; - if (i_uniqueReports) { - expectedNumSignatures = (configInfo.n + configInfo.f) / 2 + 1; - } else { - expectedNumSignatures = configInfo.f + 1; - } - - require(rs.length == expectedNumSignatures, "wrong number of signatures"); - require(rs.length == ss.length, "signatures out of registration"); - - Oracle memory transmitter = s_oracles[msg.sender]; - require( // Check that sender is authorized to report - transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index], - "unauthorized transmitter" - ); - } - - address[maxNumOracles] memory signed; - uint8 signerCount = 0; - - { - // Verify signatures attached to report - bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); - - Oracle memory o; - for (uint256 i = 0; i < rs.length; ++i) { - address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); - o = s_oracles[signer]; - require(o.role == Role.Signer, "address not authorized to sign"); - require(signed[o.index] == address(0), "non-unique signature"); - signed[o.index] = signer; - signerCount += 1; - } - } - - _report(initialGas, msg.sender, signerCount, signed, report); - } -} diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/README.md b/contracts/src/v0.8/functions/dev/v0_0_0/ocr/README.md deleted file mode 100644 index e7ccc5120b2..00000000000 --- a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# OCR2 Rapid Prototype Contracts - -The contracts in this directory are to aid rapid prototyping of OCR2 based products. They abstract OCR2 config and boilerplate code so that specific logic can be implemented and tested quickly. They are not optimized or audited. - -Do not use these contracts in production. For actual production contracts, it is expected that most of the logic of these contracts will be folded directly into the application contract. \ No newline at end of file diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol new file mode 100644 index 00000000000..e7958a7bcab --- /dev/null +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; +import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; +import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; + +import {Routable} from "./Routable.sol"; +import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; + +import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; + +/// @title Functions Billing contract +/// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). +abstract contract FunctionsBilling is Routable, IFunctionsBilling { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei + // ================================================================ + // | Request Commitment state | + // ================================================================ + + mapping(bytes32 requestId => bytes32 commitmentHash) private s_requestCommitments; + + event CommitmentDeleted(bytes32 requestId); + + // ================================================================ + // | Configuration state | + // ================================================================ + + struct Config { + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. + uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. + uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. + uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request + uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. + uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out + } + + Config private s_config; + + event ConfigUpdated(Config config); + + error UnsupportedRequestDataVersion(); + error InsufficientBalance(); + error InvalidSubscription(); + error UnauthorizedSender(); + error MustBeSubOwner(address owner); + error InvalidLinkWeiPrice(int256 linkWei); + error PaymentTooLarge(); + error NoTransmittersSet(); + error InvalidCalldata(); + + // ================================================================ + // | Balance state | + // ================================================================ + + mapping(address transmitter => uint96 balanceJuelsLink) private s_withdrawableTokens; + // Pool together collected DON fees + // Disperse them on withdrawal or change in OCR configuration + uint96 internal s_feePool; + + AggregatorV3Interface private s_linkToNativeFeed; + + // ================================================================ + // | Initialization | + // ================================================================ + constructor(address router, Config memory config, address linkToNativeFeed) Routable(router) { + s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); + + updateConfig(config); + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice Gets the Chainlink Coordinator's billing configuration + /// @return config + function getConfig() external view returns (Config memory) { + return s_config; + } + + /// @notice Sets the Chainlink Coordinator's billing configuration + /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information + function updateConfig(Config memory config) public { + _onlyOwner(); + + s_config = config; + emit ConfigUpdated(config); + } + + // ================================================================ + // | Fee Calculation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function getDONFee(bytes memory /* requestData */) public view override returns (uint72) { + return s_config.donFee; + } + + /// @inheritdoc IFunctionsBilling + function getAdminFee() public view override returns (uint72) { + return _getRouter().getAdminFee(); + } + + /// @inheritdoc IFunctionsBilling + function getWeiPerUnitLink() public view returns (uint256) { + Config memory config = s_config; + (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); + // solhint-disable-next-line not-rely-on-time + if (config.feedStalenessSeconds < block.timestamp - timestamp && config.feedStalenessSeconds > 0) { + return config.fallbackNativePerUnitLink; + } + if (weiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(weiPerUnitLink); + } + return uint256(weiPerUnitLink); + } + + function _getJuelsPerGas(uint256 gasPriceWei) private view returns (uint96) { + // (1e18 juels/link) * (wei/gas) / (wei/link) = juels per gas + // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) + return SafeCast.toUint96((1e18 * gasPriceWei) / getWeiPerUnitLink()); + } + + // ================================================================ + // | Cost Estimation | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function estimateCost( + uint64 subscriptionId, + bytes calldata data, + uint32 callbackGasLimit, + uint256 gasPriceWei + ) external view override returns (uint96) { + _getRouter().isValidCallbackGasLimit(subscriptionId, callbackGasLimit); + // Reasonable ceilings to prevent integer overflows + if (gasPriceWei > REASONABLE_GAS_PRICE_CEILING) { + revert InvalidCalldata(); + } + uint72 adminFee = getAdminFee(); + uint72 donFee = getDONFee(data); + return _calculateCostEstimate(callbackGasLimit, gasPriceWei, donFee, adminFee); + } + + /// @notice Estimate the cost in Juels of LINK + // that will be charged to a subscription to fulfill a Functions request + // Gas Price can be overestimated to account for flucuations between request and response time + function _calculateCostEstimate( + uint32 callbackGasLimit, + uint256 gasPriceWei, + uint72 donFee, + uint72 adminFee + ) internal view returns (uint96) { + uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; + + // If gas price is less than the minimum fulfillment gas price, override to using the minimum + if (gasPriceWei < s_config.minimumEstimateGasPriceWei) { + gasPriceWei = s_config.minimumEstimateGasPriceWei; + } + + uint256 gasPriceWithOverestimation = gasPriceWei + + ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); + /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units + + uint96 juelsPerGas = _getJuelsPerGas(gasPriceWithOverestimation); + uint256 estimatedGasReimbursement = juelsPerGas * executionGas; + uint96 fees = uint96(donFee) + uint96(adminFee); + + return SafeCast.toUint96(estimatedGasReimbursement + fees); + } + + // ================================================================ + // | Billing | + // ================================================================ + + /// @notice Initiate the billing process for an Functions request + /// @dev Only callable by the Functions Router + /// @param request - Chainlink Functions request data, see FunctionsResponse.RequestMeta for the structure + /// @return commitment - The parameters of the request that must be held consistent at response time + function _startBilling( + FunctionsResponse.RequestMeta memory request + ) internal returns (FunctionsResponse.Commitment memory commitment) { + Config memory config = s_config; + + // Nodes should support all past versions of the structure + if (request.dataVersion > config.maxSupportedRequestDataVersion) { + revert UnsupportedRequestDataVersion(); + } + + uint72 donFee = getDONFee(request.data); + uint96 estimatedTotalCostJuels = _calculateCostEstimate( + request.callbackGasLimit, + tx.gasprice, + donFee, + request.adminFee + ); + + // Check that subscription can afford the estimated cost + if ((request.availableBalance) < estimatedTotalCostJuels) { + revert InsufficientBalance(); + } + + uint32 timeoutTimestamp = uint32(block.timestamp + config.requestTimeoutSeconds); + bytes32 requestId = keccak256( + abi.encode( + address(this), + request.requestingContract, + request.subscriptionId, + request.initiatedRequests + 1, + keccak256(request.data), + request.dataVersion, + request.callbackGasLimit, + estimatedTotalCostJuels, + timeoutTimestamp, + // solhint-disable-next-line avoid-tx-origin + tx.origin + ) + ); + + commitment = FunctionsResponse.Commitment({ + adminFee: request.adminFee, + coordinator: address(this), + client: request.requestingContract, + subscriptionId: request.subscriptionId, + callbackGasLimit: request.callbackGasLimit, + estimatedTotalCostJuels: estimatedTotalCostJuels, + timeoutTimestamp: timeoutTimestamp, + requestId: requestId, + donFee: donFee, + gasOverheadBeforeCallback: config.gasOverheadBeforeCallback, + gasOverheadAfterCallback: config.gasOverheadAfterCallback + }); + + s_requestCommitments[requestId] = keccak256(abi.encode(commitment)); + + return commitment; + } + + /// @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription + /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @return result fulfillment result + /// @dev Only callable by a node that has been approved on the Coordinator + /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request + function _fulfillAndBill( + bytes32 requestId, + bytes memory response, + bytes memory err, + bytes memory onchainMetadata, + bytes memory /* offchainMetadata TODO: use in getDonFee() for dynamic billing */ + ) internal returns (FunctionsResponse.FulfillResult) { + FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); + + uint96 juelsPerGas = _getJuelsPerGas(tx.gasprice); + // Gas overhead without callback + uint96 gasOverheadJuels = juelsPerGas * + (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback); + + // The Functions Router will perform the callback to the client contract + (FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill( + response, + err, + juelsPerGas, + gasOverheadJuels + commitment.donFee, // costWithoutFulfillment + msg.sender, + commitment + ); + + // The router will only pay the DON on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the Coordinator should hold on to the request commitment + if ( + resultCode == FunctionsResponse.FulfillResult.FULFILLED || + resultCode == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + delete s_requestCommitments[requestId]; + // Reimburse the transmitter for the fulfillment gas cost + s_withdrawableTokens[msg.sender] = gasOverheadJuels + callbackCostJuels; + // Put donFee into the pool of fees, to be split later + // Saves on storage writes that would otherwise be charged to the user + s_feePool += commitment.donFee; + } + + return resultCode; + } + + // ================================================================ + // | Request Timeout | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Router + /// @dev Used by FunctionsRouter.sol during timeout of a request + function deleteCommitment(bytes32 requestId) external override onlyRouter { + // Delete commitment + delete s_requestCommitments[requestId]; + emit CommitmentDeleted(requestId); + } + + // ================================================================ + // | Fund withdrawal | + // ================================================================ + + /// @inheritdoc IFunctionsBilling + function oracleWithdraw(address recipient, uint96 amount) external { + _disperseFeePool(); + + if (amount == 0) { + amount = s_withdrawableTokens[msg.sender]; + } else if (s_withdrawableTokens[msg.sender] < amount) { + revert InsufficientBalance(); + } + s_withdrawableTokens[msg.sender] -= amount; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(recipient, amount); + } + + /// @inheritdoc IFunctionsBilling + /// @dev Only callable by the Coordinator owner + function oracleWithdrawAll() external { + _onlyOwner(); + _disperseFeePool(); + + address[] memory transmitters = _getTransmitters(); + + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < transmitters.length; ++i) { + uint96 balance = s_withdrawableTokens[transmitters[i]]; + if (balance > 0) { + s_withdrawableTokens[transmitters[i]] = 0; + IFunctionsSubscriptions(address(_getRouter())).oracleWithdraw(transmitters[i], balance); + } + } + } + + // Overriden in FunctionsCoordinator, which has visibility into transmitters + function _getTransmitters() internal view virtual returns (address[] memory); + + // DON fees are collected into a pool s_feePool + // When OCR configuration changes, or any oracle withdraws, this must be dispersed + function _disperseFeePool() internal { + if (s_feePool == 0) { + return; + } + // All transmitters are assumed to also be observers + // Pay out the DON fee to all transmitters + address[] memory transmitters = _getTransmitters(); + if (transmitters.length == 0) { + revert NoTransmittersSet(); + } + uint96 feePoolShare = s_feePool / uint96(transmitters.length); + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < transmitters.length; ++i) { + s_withdrawableTokens[transmitters[i]] += feePoolShare; + } + s_feePool -= feePoolShare * uint96(transmitters.length); + } + + // Overriden in FunctionsCoordinator.sol + function _onlyOwner() internal view virtual; +} diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol new file mode 100644 index 00000000000..6d033d4b235 --- /dev/null +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsClient.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol"; +import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol"; + +import {FunctionsRequest} from "./libraries/FunctionsRequest.sol"; + +/// @title The Chainlink Functions client contract +/// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests +abstract contract FunctionsClient is IFunctionsClient { + using FunctionsRequest for FunctionsRequest.Request; + + IFunctionsRouter internal immutable i_router; + + event RequestSent(bytes32 indexed id); + event RequestFulfilled(bytes32 indexed id); + + error OnlyRouterCanFulfill(); + + constructor(address router) { + i_router = IFunctionsRouter(router); + } + + /// @notice Sends a Chainlink Functions request + /// @param data The CBOR encoded bytes data for a Functions request + /// @param subscriptionId The subscription ID that will be charged to service the request + /// @param callbackGasLimit the amount of gas that will be available for the fulfillment callback + /// @return requestId The generated request ID for this request + function _sendRequest( + bytes memory data, + uint64 subscriptionId, + uint32 callbackGasLimit, + bytes32 donId + ) internal returns (bytes32) { + bytes32 requestId = i_router.sendRequest( + subscriptionId, + data, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + donId + ); + emit RequestSent(requestId); + return requestId; + } + + /// @notice User defined function to handle a response from the DON + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the execution of the user's source code + /// @param err Aggregated error from the execution of the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual; + + /// @inheritdoc IFunctionsClient + function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override { + if (msg.sender != address(i_router)) { + revert OnlyRouterCanFulfill(); + } + _fulfillRequest(requestId, response, err); + emit RequestFulfilled(requestId); + } +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol similarity index 97% rename from contracts/src/v0.8/functions/dev/v1_0_0/FunctionsCoordinator.sol rename to contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index 540b382d652..eb0d954ae02 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.19; import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; -import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {FunctionsBilling} from "./FunctionsBilling.sol"; @@ -11,14 +10,14 @@ import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; /// @title Functions Coordinator contract /// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with -/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; /// @inheritdoc ITypeAndVersion - string public constant override typeAndVersion = "Functions Coordinator v1.0.0"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "Functions Coordinator v1.1.0"; event OracleRequest( bytes32 indexed requestId, @@ -100,6 +99,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli emit OracleRequest( commitment.requestId, request.requestingContract, + // solhint-disable-next-line avoid-tx-origin tx.origin, request.subscriptionId, request.subscriptionOwner, diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol similarity index 99% rename from contracts/src/v0.8/functions/dev/v1_0_0/FunctionsRouter.sol rename to contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index 41cd90341f3..8daa821bb54 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -18,6 +18,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, using FunctionsResponse for FunctionsResponse.Commitment; using FunctionsResponse for FunctionsResponse.FulfillResult; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Router v1.0.0"; // We limit return data to a selector plus 4 words. This is to avoid @@ -285,6 +286,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, subscriptionId: subscriptionId, subscriptionOwner: subscription.owner, requestingContract: msg.sender, + // solhint-disable-next-line avoid-tx-origin requestInitiator: tx.origin, data: data, dataVersion: dataVersion, @@ -402,7 +404,6 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, address client ) private returns (CallbackResult memory) { bool destinationNoLongerExists; - // solhint-disable-next-line no-inline-assembly assembly { // solidity calls check that a contract actually exists at the destination, so we do the same destinationNoLongerExists := iszero(extcodesize(client)) @@ -432,7 +433,6 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, // allocate return data memory ahead of time bytes memory returnData = new bytes(MAX_CALLBACK_RETURN_BYTES); - // solhint-disable-next-line no-inline-assembly assembly { let g := gas() // Compute g -= gasForCallExactCheck and check for underflow diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol similarity index 98% rename from contracts/src/v0.8/functions/dev/v1_0_0/FunctionsSubscriptions.sol rename to contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol index 864225fd38c..86e762e39c8 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsSubscriptions.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsSubscriptions.sol @@ -3,19 +3,15 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; -import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; -import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; -import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; /// @title Functions Subscriptions contract /// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). -/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Receiver { using SafeERC20 for IERC20; using FunctionsResponse for FunctionsResponse.Commitment; diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/Routable.sol b/contracts/src/v0.8/functions/dev/v1_X/Routable.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/Routable.sol rename to contracts/src/v0.8/functions/dev/v1_X/Routable.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol similarity index 98% rename from contracts/src/v0.8/functions/dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol rename to contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index c4bd524b522..fbeef3c298a 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -16,6 +16,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, using EnumerableSet for EnumerableSet.AddressSet; /// @inheritdoc ITypeAndVersion + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; EnumerableSet.AddressSet private s_allowedSenders; diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol rename to contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol diff --git a/contracts/src/v0.8/functions/dev/v1_X/example/FunctionsClientExample.sol b/contracts/src/v0.8/functions/dev/v1_X/example/FunctionsClientExample.sol new file mode 100644 index 00000000000..abb8569b1e6 --- /dev/null +++ b/contracts/src/v0.8/functions/dev/v1_X/example/FunctionsClientExample.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsClient} from "../FunctionsClient.sol"; +import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; +import {FunctionsRequest} from "../libraries/FunctionsRequest.sol"; + +/// @title Chainlink Functions example Client contract implementation +contract FunctionsClientExample is FunctionsClient, ConfirmedOwner { + using FunctionsRequest for FunctionsRequest.Request; + + uint32 public constant MAX_CALLBACK_GAS = 70_000; + + bytes32 public s_lastRequestId; + bytes32 public s_lastResponse; + bytes32 public s_lastError; + uint32 public s_lastResponseLength; + uint32 public s_lastErrorLength; + + error UnexpectedRequestID(bytes32 requestId); + + constructor(address router) FunctionsClient(router) ConfirmedOwner(msg.sender) {} + + /// @notice Send a simple request + /// @param source JavaScript source code + /// @param encryptedSecretsReferences Encrypted secrets payload + /// @param args List of arguments accessible from within the source code + /// @param subscriptionId Billing ID + function sendRequest( + string calldata source, + bytes calldata encryptedSecretsReferences, + string[] calldata args, + uint64 subscriptionId, + bytes32 jobId + ) external onlyOwner { + FunctionsRequest.Request memory req; + req._initializeRequestForInlineJavaScript(source); + if (encryptedSecretsReferences.length > 0) req._addSecretsReference(encryptedSecretsReferences); + if (args.length > 0) req._setArgs(args); + s_lastRequestId = _sendRequest(req._encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, jobId); + } + + /// @notice Store latest result/error + /// @param requestId The request ID, returned by sendRequest() + /// @param response Aggregated response from the user code + /// @param err Aggregated error from the user code or from the execution pipeline + /// @dev Either response or error parameter will be set, but never both + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { + if (s_lastRequestId != requestId) { + revert UnexpectedRequestID(requestId); + } + // Save only the first 32 bytes of response/error to always fit within MAX_CALLBACK_GAS + s_lastResponse = _bytesToBytes32(response); + s_lastResponseLength = uint32(response.length); + s_lastError = _bytesToBytes32(err); + s_lastErrorLength = uint32(err.length); + } + + function _bytesToBytes32(bytes memory b) private pure returns (bytes32 out) { + uint256 maxLen = 32; + if (b.length < 32) { + maxLen = b.length; + } + for (uint256 i = 0; i < maxLen; ++i) { + out |= bytes32(b[i]) >> (i * 8); + } + return out; + } +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsBilling.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsClient.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsClient.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsClient.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsClient.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsCoordinator.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsCoordinator.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsCoordinator.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsRouter.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsRouter.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsRouter.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsSubscriptions.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsSubscriptions.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IFunctionsSubscriptions.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsSubscriptions.sol diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/interfaces/IOwnableFunctionsRouter.sol rename to contracts/src/v0.8/functions/dev/v1_X/interfaces/IOwnableFunctionsRouter.sol diff --git a/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsRequest.sol b/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsRequest.sol new file mode 100644 index 00000000000..4e3134dc127 --- /dev/null +++ b/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsRequest.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; + +/// @title Library for encoding the input data of a Functions request into CBOR +library FunctionsRequest { + using CBOR for CBOR.CBORBuffer; + + uint16 public constant REQUEST_DATA_VERSION = 1; + uint256 internal constant DEFAULT_BUFFER_SIZE = 256; + + enum Location { + Inline, // Provided within the Request + Remote, // Hosted through remote location that can be accessed through a provided URL + DONHosted // Hosted on the DON's storage + } + + enum CodeLanguage { + JavaScript + // In future version we may add other languages + } + + struct Request { + Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON + Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported + CodeLanguage language; // ════════════╸ The coding language that the source code is written in + string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted + bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets()) + string[] args; // ════════════════════╸ String arguments that will be passed into the source code + bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code + } + + error EmptySource(); + error EmptySecrets(); + error EmptyArgs(); + error NoInlineSecrets(); + + /// @notice Encodes a Request to CBOR encoded bytes + /// @param self The request to encode + /// @return CBOR encoded bytes + function _encodeCBOR(Request memory self) internal pure returns (bytes memory) { + CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); + + buffer.writeString("codeLocation"); + buffer.writeUInt256(uint256(self.codeLocation)); + + buffer.writeString("language"); + buffer.writeUInt256(uint256(self.language)); + + buffer.writeString("source"); + buffer.writeString(self.source); + + if (self.args.length > 0) { + buffer.writeString("args"); + buffer.startArray(); + for (uint256 i = 0; i < self.args.length; ++i) { + buffer.writeString(self.args[i]); + } + buffer.endSequence(); + } + + if (self.encryptedSecretsReference.length > 0) { + if (self.secretsLocation == Location.Inline) { + revert NoInlineSecrets(); + } + buffer.writeString("secretsLocation"); + buffer.writeUInt256(uint256(self.secretsLocation)); + buffer.writeString("secrets"); + buffer.writeBytes(self.encryptedSecretsReference); + } + + if (self.bytesArgs.length > 0) { + buffer.writeString("bytesArgs"); + buffer.startArray(); + for (uint256 i = 0; i < self.bytesArgs.length; ++i) { + buffer.writeBytes(self.bytesArgs[i]); + } + buffer.endSequence(); + } + + return buffer.buf.buf; + } + + /// @notice Initializes a Chainlink Functions Request + /// @dev Sets the codeLocation and code on the request + /// @param self The uninitialized request + /// @param codeLocation The user provided source code location + /// @param language The programming language of the user code + /// @param source The user provided source code or a url + function _initializeRequest( + Request memory self, + Location codeLocation, + CodeLanguage language, + string memory source + ) internal pure { + if (bytes(source).length == 0) revert EmptySource(); + + self.codeLocation = codeLocation; + self.language = language; + self.source = source; + } + + /// @notice Initializes a Chainlink Functions Request + /// @dev Simplified version of initializeRequest for PoC + /// @param self The uninitialized request + /// @param javaScriptSource The user provided JS code (must not be empty) + function _initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { + _initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); + } + + /// @notice Adds Remote user encrypted secrets to a Request + /// @param self The initialized request + /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets + function _addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure { + if (encryptedSecretsReference.length == 0) revert EmptySecrets(); + + self.secretsLocation = Location.Remote; + self.encryptedSecretsReference = encryptedSecretsReference; + } + + /// @notice Adds DON-hosted secrets reference to a Request + /// @param self The initialized request + /// @param slotID Slot ID of the user's secrets hosted on DON + /// @param version User data version (for the slotID) + function _addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { + CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); + + buffer.writeString("slotID"); + buffer.writeUInt64(slotID); + buffer.writeString("version"); + buffer.writeUInt64(version); + + self.secretsLocation = Location.DONHosted; + self.encryptedSecretsReference = buffer.buf.buf; + } + + /// @notice Sets args for the user run function + /// @param self The initialized request + /// @param args The array of string args (must not be empty) + function _setArgs(Request memory self, string[] memory args) internal pure { + if (args.length == 0) revert EmptyArgs(); + + self.args = args; + } + + /// @notice Sets bytes args for the user run function + /// @param self The initialized request + /// @param args The array of bytes args (must not be empty) + function _setBytesArgs(Request memory self, bytes[] memory args) internal pure { + if (args.length == 0) revert EmptyArgs(); + + self.bytesArgs = args; + } +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsResponse.sol b/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsResponse.sol similarity index 97% rename from contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsResponse.sol rename to contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsResponse.sol index 31a33169226..65fad665d69 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsResponse.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/libraries/FunctionsResponse.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {IFunctionsSubscriptions} from "../interfaces/IFunctionsSubscriptions.sol"; - /// @title Library of types that are used for fulfillment of a Functions request library FunctionsResponse { // Used to send request information from the Router to the Coordinator diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/mocks/FunctionsV1EventsMock.sol b/contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/mocks/FunctionsV1EventsMock.sol rename to contracts/src/v0.8/functions/dev/v1_X/mocks/FunctionsV1EventsMock.sol diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Abstract.sol b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Abstract.sol similarity index 83% rename from contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Abstract.sol rename to contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Abstract.sol index 08dcae6d48e..77cc9502171 100644 --- a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Abstract.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Abstract.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.19; import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { // Maximum number of oracles the offchain reporting protocol is designed for - uint256 internal constant maxNumOracles = 31; + uint256 internal constant MAX_NUM_ORACLES = 31; /** * @notice triggers a new run of the offchain reporting protocol @@ -61,37 +61,6 @@ abstract contract OCR2Abstract is ITypeAndVersion { virtual returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); - function _configDigestFromConfigData( - uint256 chainId, - address contractAddress, - uint64 configCount, - address[] memory signers, - address[] memory transmitters, - uint8 f, - bytes memory onchainConfig, - uint64 offchainConfigVersion, - bytes memory offchainConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - chainId, - contractAddress, - configCount, - signers, - transmitters, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - /** * @notice optionally emited to indicate the latest configDigest and epoch for which a report was successfully transmited. Alternatively, the contract may diff --git a/contracts/src/v0.8/dev/ocr2/OCR2Base.sol b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol similarity index 85% rename from contracts/src/v0.8/dev/ocr2/OCR2Base.sol rename to contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol index 5e50d99f213..dd9ea84a519 100644 --- a/contracts/src/v0.8/dev/ocr2/OCR2Base.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol @@ -1,21 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/access/ConfirmedOwner.sol"; -import "./OCR2Abstract.sol"; +import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; +import {OCR2Abstract} from "./OCR2Abstract.sol"; /** * @notice Onchain verification of reports from the offchain reporting protocol - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. * @dev For details on its operation, see the offchain reporting protocol design * doc, which refers to this contract as simply the "contract". - * @dev This contract is meant to aid rapid development of new applications based on OCR2. - * However, for actual production contracts, it is expected that most of the logic of this contract - * will be folded directly into the application contract. Inheritance prevents us from doing lots - * of juicy storage layout optimizations, leading to a substantial increase in gas cost. */ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { error ReportInvalid(); + error InvalidConfig(string message); bool internal immutable i_uniqueReports; @@ -23,8 +19,15 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { i_uniqueReports = uniqueReports; } + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 private constant maxUint32 = (1 << 32) - 1; + // incremented each time a new config is posted. This count is incorporated + // into the config digest, to prevent replay attacks. + uint32 internal s_configCount; + uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems + // to extract config from logs. + // Storing these fields used on the hot path in a ConfigInfo variable reduces the // retrieval of all of them to a single SLOAD. If any further fields are // added, make sure that storage of the struct still takes at most 32 bytes. @@ -35,12 +38,6 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { } ConfigInfo internal s_configInfo; - // incremented each time a new config is posted. This count is incorporated - // into the config digest, to prevent replay attacks. - uint32 internal s_configCount; - uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems - // to extract config from logs. - // Used for s_oracles[a].role, where a is an address, to track the purpose // of the address, or to indicate that the address is unset. enum Role { @@ -60,7 +57,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { Role role; // Role of the address which mapped to this struct } - mapping(address => Oracle) /* signer OR transmitter address */ internal s_oracles; + mapping(address signerOrTransmitter => Oracle) internal s_oracles; // s_signers contains the signing address of each oracle address[] internal s_signers; @@ -75,14 +72,14 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { // Reverts transaction if config args are invalid modifier checkConfigValid( - uint256 _numSigners, - uint256 _numTransmitters, - uint256 _f + uint256 numSigners, + uint256 numTransmitters, + uint256 f ) { - require(_numSigners <= maxNumOracles, "too many signers"); - require(_f > 0, "f must be positive"); - require(_numSigners == _numTransmitters, "oracle addresses out of registration"); - require(_numSigners > 3 * _f, "faulty-oracle f too high"); + if (numSigners > MAX_NUM_ORACLES) revert InvalidConfig("too many signers"); + if (f == 0) revert InvalidConfig("f must be positive"); + if (numSigners != numTransmitters) revert InvalidConfig("oracle addresses out of registration"); + if (numSigners <= 3 * f) revert InvalidConfig("faulty-oracle f too high"); _; } @@ -145,10 +142,13 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { s_transmitters.pop(); } - for (uint256 i = 0; i < args.signers.length; ++i) { + // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol + for (uint256 i = 0; i < args.signers.length; i++) { // add new signer/transmitter addresses + // solhint-disable-next-line custom-errors require(s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address"); s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); + // solhint-disable-next-line custom-errors require(s_oracles[args.transmitters[i]].role == Role.Unset, "repeated transmitter address"); s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); s_signers.push(args.signers[i]); @@ -159,7 +159,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { s_latestConfigBlockNumber = uint32(block.number); s_configCount += 1; { - s_configInfo.latestConfigDigest = configDigestFromConfigData( + s_configInfo.latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), s_configCount, @@ -184,11 +184,9 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { args.offchainConfigVersion, args.offchainConfig ); - - _afterSetConfig(args.f, args.onchainConfig); } - function configDigestFromConfigData( + function _configDigestFromConfigData( uint256 _chainId, address _contractAddress, uint64 _configCount, @@ -223,7 +221,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see configDigestFromConfigData) + * @return configDigest domain-separation tag for current config (see __configDigestFromConfigData) */ function latestConfigDetails() external @@ -244,20 +242,6 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - - /** - * @dev hook to allow additional validation of the report by the extending contract - * @param configDigest separation tag for current config (see configDigestFromConfigData) - * @param epochAndRound 27 byte padding, 4-byte epoch and 1-byte round - * @param report serialized report - */ - function _validateReport( - bytes32 configDigest, - uint40 epochAndRound, - bytes memory report - ) internal virtual returns (bool); - /** * @dev hook called after the report has been fully validated * for the extending contract to handle additional logic, such as oracle payment @@ -270,7 +254,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { uint256 initialGas, address transmitter, uint8 signerCount, - address[maxNumOracles] memory signers, + address[MAX_NUM_ORACLES] memory signers, bytes calldata report ) internal virtual; @@ -290,7 +274,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { 32 + // word containing length of ss 0; // placeholder - function requireExpectedMsgDataLength( + function _requireExpectedMsgDataLength( bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss @@ -303,6 +287,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { ss.length * 32 + // 32 bytes per entry in _ss 0; // placeholder + // solhint-disable-next-line custom-errors require(msg.data.length == expected, "calldata length mismatch"); } @@ -332,16 +317,13 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { bytes32 configDigest = reportContext[0]; uint32 epochAndRound = uint32(uint256(reportContext[1])); - if (!_validateReport(configDigest, epochAndRound, report)) { - revert ReportInvalid(); - } - emit Transmitted(configDigest, uint32(epochAndRound >> 8)); ConfigInfo memory configInfo = s_configInfo; + // solhint-disable-next-line custom-errors require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); - requireExpectedMsgDataLength(report, rs, ss); + _requireExpectedMsgDataLength(report, rs, ss); uint256 expectedNumSignatures; if (i_uniqueReports) { @@ -350,17 +332,20 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { expectedNumSignatures = configInfo.f + 1; } + // solhint-disable-next-line custom-errors require(rs.length == expectedNumSignatures, "wrong number of signatures"); + // solhint-disable-next-line custom-errors require(rs.length == ss.length, "signatures out of registration"); Oracle memory transmitter = s_oracles[msg.sender]; + // solhint-disable-next-line custom-errors require( // Check that sender is authorized to report transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index], "unauthorized transmitter" ); } - address[maxNumOracles] memory signed; + address[MAX_NUM_ORACLES] memory signed; uint8 signerCount = 0; { @@ -368,10 +353,13 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); Oracle memory o; + // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol for (uint256 i = 0; i < rs.length; ++i) { address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); o = s_oracles[signer]; + // solhint-disable-next-line custom-errors require(o.role == Role.Signer, "address not authorized to sign"); + // solhint-disable-next-line custom-errors require(signed[o.index] == address(0), "non-unique signature"); signed[o.index] = signer; signerCount += 1; diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/BaseTest.t.sol b/contracts/src/v0.8/functions/tests/v0_0_0/BaseTest.t.sol deleted file mode 100644 index 6463b2b94b6..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/BaseTest.t.sol +++ /dev/null @@ -1,17 +0,0 @@ -pragma solidity ^0.8.6; - -import {Test} from "forge-std/Test.sol"; - -contract BaseTest is Test { - bool private s_baseTestInitialized; - address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; - - function setUp() public virtual { - // BaseTest.setUp is often called multiple times from tests' setUp due to inheritance. - if (s_baseTestInitialized) return; - s_baseTestInitialized = true; - - // Set msg.sender to OWNER until changePrank or stopPrank is called - vm.startPrank(OWNER); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/FunctionsOracle.t.sol b/contracts/src/v0.8/functions/tests/v0_0_0/FunctionsOracle.t.sol deleted file mode 100644 index ab175c3c45d..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/FunctionsOracle.t.sol +++ /dev/null @@ -1,144 +0,0 @@ -pragma solidity ^0.8.6; - -import {BaseTest} from "./BaseTest.t.sol"; -import {FunctionsOracle, FunctionsOracleWithInit} from "./testhelpers/FunctionsOracleWithInit.sol"; -import {FunctionsBillingRegistryWithInit} from "./testhelpers/FunctionsBillingRegistryWithInit.sol"; -import {ConfirmedOwnerUpgradeable} from "../../dev/v0_0_0/accessControl/ConfirmedOwnerUpgradeable.sol"; - -// import {LinkToken} from "../../../../src/v0.4/LinkToken.sol"; -// import {MockV3Aggregator} from "../../../../src/v0.7/tests/MockV3Aggregator.sol"; - -contract FunctionsOracleSetup is BaseTest { - bytes constant DATA = abi.encode("bytes"); - address registryAddress = makeAddr("Registry"); - - FunctionsOracleWithInit s_oracle; - - function setUp() public virtual override { - BaseTest.setUp(); - - s_oracle = new FunctionsOracleWithInit(); - } -} - -contract FunctionsOracle_typeAndVersion is FunctionsOracleSetup { - function testTypeAndVersionSuccess() public { - assertEq(s_oracle.typeAndVersion(), "FunctionsOracle 0.0.0"); - } -} - -contract FunctionsOracle_setDONPublicKey is FunctionsOracleSetup { - function testSetDONPublicKey_gas() public { - s_oracle.setDONPublicKey(DATA); - } - - function testSetDONPublicKeySuccess() public { - bytes memory donPublicKey = abi.encode("newKey"); - - // Verify the existing key is different from the new key - bytes memory existingDonPublicKey = s_oracle.getDONPublicKey(); - bytes memory expectedExistingDonPublicKey; - assertEq(existingDonPublicKey, expectedExistingDonPublicKey); - // If they have different lengths they are not the same - assertFalse(donPublicKey.length == expectedExistingDonPublicKey.length); - - s_oracle.setDONPublicKey(donPublicKey); - bytes memory newDonPublicKey = s_oracle.getDONPublicKey(); - assertEq(newDonPublicKey, donPublicKey); - } - - // Reverts - - function testEmptyPublicKeyReverts() public { - bytes memory donPublicKey; - - vm.expectRevert(FunctionsOracle.EmptyPublicKey.selector); - s_oracle.setDONPublicKey(donPublicKey); - } - - function testOnlyOwnerReverts() public { - vm.stopPrank(); - vm.expectRevert(ConfirmedOwnerUpgradeable.OnlyCallableByOwner.selector); - - bytes memory donPublicKey; - s_oracle.setDONPublicKey(donPublicKey); - } -} - -contract FunctionsOracle_setRegistry is FunctionsOracleSetup { - function testSetRegistry_gas() public { - s_oracle.setRegistry(registryAddress); - } - - function testSetRegistrySuccess() public { - address registryAddress = makeAddr("newRegistry"); - - // Verify the existing key is different from the new key - address existingRegistryAddress = s_oracle.getRegistry(); - address expectedRegistryAddress; - assertEq(existingRegistryAddress, expectedRegistryAddress); - - s_oracle.setRegistry(registryAddress); - address newRegistryAddress = s_oracle.getRegistry(); - assertEq(registryAddress, newRegistryAddress); - } - - // Reverts - - function testEmptyPublicKeyReverts() public { - address registryAddress; - - vm.expectRevert(FunctionsOracle.EmptyBillingRegistry.selector); - s_oracle.setRegistry(registryAddress); - } - - function testOnlyOwnerReverts() public { - vm.stopPrank(); - vm.expectRevert(ConfirmedOwnerUpgradeable.OnlyCallableByOwner.selector); - - address registryAddress; - s_oracle.setRegistry(registryAddress); - } -} - -contract FunctionsOracle_sendRequest is FunctionsOracleSetup { - FunctionsBillingRegistryWithInit s_registry; - - // LinkToken s_link; - // MockV3Aggregator s_linketh; - - function setUp() public virtual override { - FunctionsOracleSetup.setUp(); - - // s_link = new LinkToken(); - // s_linketh = new MockV3Aggregator(0, 5021530000000000); - s_registry = new FunctionsBillingRegistryWithInit(makeAddr("Link Token"), makeAddr("Link Eth"), address(s_oracle)); - s_oracle.setRegistry(address(s_registry)); - s_oracle.deactivateAuthorizedReceiver(); - } - - event OracleRequest(bytes32 requestId, bytes data); - - // TODO: write new ^0.8.0 mocks for LinkToken & MockV3Aggregator - // function testSendRequest_gas() public { - // s_oracle.sendRequest(0, DATA, 0); - // } - - // function testSendRequestFuzzSuccess(uint64 subscriptionId, bytes calldata data) public { - // vm.assume(data.length != 0); - - // vm.expectEmit(false, false, false, false); - // emit OracleRequest(0, data); - - // s_oracle.sendRequest(subscriptionId, data, 0); - // } - - // Reverts - - function testEmptyRequestDataReverts() public { - bytes memory emptyData; - - vm.expectRevert(FunctionsOracle.EmptyRequestData.selector); - s_oracle.sendRequest(0, emptyData, 0); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedOriginReceiverTestHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedOriginReceiverTestHelper.sol deleted file mode 100644 index 0c592ae81c6..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedOriginReceiverTestHelper.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../../../dev/v0_0_0/accessControl/AuthorizedOriginReceiver.sol"; - -contract AuthorizedOriginReceiverTestHelper is AuthorizedOriginReceiver { - bool private s_canSetAuthorizedSenders = true; - - function changeSetAuthorizedSender(bool on) external { - s_canSetAuthorizedSenders = on; - } - - function verifyValidateAuthorizedSender() external view validateAuthorizedSender returns (bool) { - return true; - } - - function _canSetAuthorizedSenders() internal view override returns (bool) { - return s_canSetAuthorizedSenders; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedReceiverTestHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedReceiverTestHelper.sol deleted file mode 100644 index ee541013f45..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedReceiverTestHelper.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../../../dev/v0_0_0/accessControl/AuthorizedReceiver.sol"; - -contract AuthorizedReceiverTestHelper is AuthorizedReceiver { - bool private s_canSetAuthorizedSenders = true; - - function changeSetAuthorizedSender(bool on) external { - s_canSetAuthorizedSenders = on; - } - - function verifyValidateAuthorizedSender() external view validateAuthorizedSender returns (bool) { - return true; - } - - function _canSetAuthorizedSenders() internal view override returns (bool) { - return s_canSetAuthorizedSenders; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol deleted file mode 100644 index 0ace817fa52..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsBillingRegistry} from "../../../dev/v0_0_0/FunctionsBillingRegistry.sol"; - -contract FunctionsBillingRegistryWithInit is FunctionsBillingRegistry { - constructor(address link, address linkEthFeed, address oracle) { - initialize(link, linkEthFeed, oracle); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol deleted file mode 100644 index 89366510da7..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsClient, Functions} from "../../../dev/v0_0_0/FunctionsClient.sol"; - -contract FunctionsClientTestHelper is FunctionsClient { - using Functions for Functions.Request; - - event SendRequestInvoked(bytes32 requestId, string sourceCode, uint64 subscriptionId); - event FulfillRequestInvoked(bytes32 requestId, bytes response, bytes err); - - bool private s_revertFulfillRequest; - bool private s_doInvalidOperation; - - constructor(address oracle) FunctionsClient(oracle) {} - - function sendSimpleRequestWithJavaScript( - string memory sourceCode, - uint64 subscriptionId - ) public returns (bytes32 requestId) { - Functions.Request memory request; - request.initializeRequestForInlineJavaScript(sourceCode); - requestId = sendRequest(request, subscriptionId, 20_000); - emit SendRequestInvoked(requestId, sourceCode, subscriptionId); - } - - function estimateJuelCost( - string memory sourceCode, - uint64 subscriptionId, - uint256 gasCost - ) public view returns (uint96) { - Functions.Request memory request; - request.initializeRequestForInlineJavaScript(sourceCode); - return estimateCost(request, subscriptionId, 20_000, gasCost); - } - - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { - if (s_revertFulfillRequest) { - revert("asked to revert"); - } - if (s_doInvalidOperation) { - uint256 x = 1; - uint256 y = 0; - x = x / y; - } - emit FulfillRequestInvoked(requestId, response, err); - } - - function setRevertFulfillRequest(bool on) external { - s_revertFulfillRequest = on; - } - - function setDoInvalidOperation(bool on) external { - s_doInvalidOperation = on; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol deleted file mode 100644 index 4ecc15b48c9..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracleWithInit} from "./FunctionsOracleWithInit.sol"; - -contract FunctionsOracleHelper is FunctionsOracleWithInit { - function callValidateReport(bytes calldata report) external pure returns (bool isValid) { - bytes32 configDigest; - uint40 epochAndRound; - isValid = _validateReport(configDigest, epochAndRound, report); - } - - function callReport(bytes calldata report) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - _report(gasleft(), msg.sender, 1, signers, report); - } - - function callReportMultipleSigners(bytes calldata report, address secondSigner) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - signers[1] = secondSigner; - _report(gasleft(), msg.sender, 2, signers, report); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleMigrationHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleMigrationHelper.sol deleted file mode 100644 index e70fed0b7a1..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleMigrationHelper.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracleMigration} from "./mocks/FunctionsOracleMigration.sol"; - -contract FunctionsOracleMigrationHelper is FunctionsOracleMigration { - function callValidateReport(bytes calldata report) external pure returns (bool isValid) { - bytes32 configDigest; - uint40 epochAndRound; - isValid = _validateReport(configDigest, epochAndRound, report); - } - - function callReport(bytes calldata report) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - _report(gasleft(), msg.sender, 1, signers, report); - } - - function callReportMultipleSigners(bytes calldata report, address secondSigner) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - signers[1] = secondSigner; - _report(gasleft(), msg.sender, 2, signers, report); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleOriginalHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleOriginalHelper.sol deleted file mode 100644 index 4d7102a71c3..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleOriginalHelper.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracleOriginal} from "./mocks/FunctionsOracleOriginal.sol"; - -contract FunctionsOracleOriginalHelper is FunctionsOracleOriginal { - function callValidateReport(bytes calldata report) external pure returns (bool isValid) { - bytes32 configDigest; - uint40 epochAndRound; - isValid = _validateReport(configDigest, epochAndRound, report); - } - - function callReport(bytes calldata report) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - _report(gasleft(), msg.sender, 1, signers, report); - } - - function callReportMultipleSigners(bytes calldata report, address secondSigner) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - signers[1] = secondSigner; - _report(gasleft(), msg.sender, 2, signers, report); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleUpgradeableHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleUpgradeableHelper.sol deleted file mode 100644 index d11d22372db..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleUpgradeableHelper.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracle} from "../../../dev/v0_0_0/FunctionsOracle.sol"; - -contract FunctionsOracleUpgradeableHelper is FunctionsOracle { - function callValidateReport(bytes calldata report) external pure returns (bool isValid) { - bytes32 configDigest; - uint40 epochAndRound; - isValid = _validateReport(configDigest, epochAndRound, report); - } - - function callReport(bytes calldata report) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - _report(gasleft(), msg.sender, 1, signers, report); - } - - function callReportMultipleSigners(bytes calldata report, address secondSigner) external { - address[maxNumOracles] memory signers; - signers[0] = msg.sender; - signers[1] = secondSigner; - _report(gasleft(), msg.sender, 2, signers, report); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleWithInit.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleWithInit.sol deleted file mode 100644 index c5b913e9e97..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleWithInit.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracle} from "../../../dev/v0_0_0/FunctionsOracle.sol"; - -contract FunctionsOracleWithInit is FunctionsOracle { - constructor() { - initialize(); - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsTestHelper.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsTestHelper.sol deleted file mode 100644 index 5c942936d4a..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsTestHelper.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {Functions} from "../../../dev/v0_0_0/Functions.sol"; - -contract FunctionsTestHelper { - using Functions for Functions.Request; - - error EmptySource(); - error EmptyUrl(); - error EmptySecrets(); - error EmptyArgs(); - - Functions.Request private s_req; - - event RequestData(bytes data); - - function closeEvent() public { - emit RequestData(s_req.encodeCBOR()); - } - - function initializeRequestForInlineJavaScript(string memory sourceCode) public { - Functions.Request memory r; - r.initializeRequestForInlineJavaScript(sourceCode); - storeRequest(r); - } - - function addSecrets(bytes memory secrets) public { - Functions.Request memory r = s_req; - r.addRemoteSecrets(secrets); - storeRequest(r); - } - - function addEmptyArgs() public pure { - Functions.Request memory r; - string[] memory args; - r.addArgs(args); - } - - function addTwoArgs(string memory arg1, string memory arg2) public { - string[] memory args = new string[](2); - args[0] = arg1; - args[1] = arg2; - Functions.Request memory r = s_req; - r.addArgs(args); - storeRequest(r); - } - - function storeRequest(Functions.Request memory r) private { - s_req.codeLocation = r.codeLocation; - s_req.language = r.language; - s_req.source = r.source; - s_req.args = r.args; - s_req.secretsLocation = r.secretsLocation; - s_req.secrets = r.secrets; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverInterface.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverInterface.sol deleted file mode 100644 index 5f3567613dd..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverInterface.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @notice Modified AuthorizedReciever abstract for use on the Functions Oracle contract to limit usage - * @notice Uses tx.origin instead of msg.sender because the client contract sends messages to the Oracle contract - */ - -interface AuthorizedOriginReceiverInterface { - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function authorizedReceiverActive() external view returns (bool); - - /** - * @dev Triggers AuthorizedOriginReceiver usage to block unuthorized senders. - * - * Requirements: - * - * - The contract must not be deactive. - */ - function activateAuthorizedReceiver() external; - - /** - * @dev Triggers AuthorizedOriginReceiver usage to allow all senders. - * - * Requirements: - * - * - The contract must be active. - */ - function deactivateAuthorizedReceiver() external; - - /** - * @notice Sets the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to grant access - */ - function addAuthorizedSenders(address[] calldata senders) external; - - /** - * @notice Remove the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to revoke access - */ - function removeAuthorizedSenders(address[] calldata senders) external; - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() external view returns (address[] memory); - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) external view returns (bool); -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverUpgradeable.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverUpgradeable.sol deleted file mode 100644 index 4c963e46c86..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedOriginReceiverUpgradeable.sol +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {EnumerableSet} from "../../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; -import {AuthorizedOriginReceiverInterface} from "./AuthorizedOriginReceiverInterface.sol"; - -/** - * @notice Modified AuthorizedReciever abstract for use on the FunctionsOracle contract to limit usage - * @notice Uses tx.origin instead of msg.sender because the client contract sends messages to the Oracle contract - */ - -abstract contract AuthorizedOriginReceiverUpgradeable is Initializable, AuthorizedOriginReceiverInterface { - using EnumerableSet for EnumerableSet.AddressSet; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - event AuthorizedSendersActive(address account); - event AuthorizedSendersDeactive(address account); - - error EmptySendersList(); - error UnauthorizedSender(); - error NotAllowedToSetSenders(); - error AlreadySet(); - - bool private s_active; - EnumerableSet.AddressSet private s_authorizedSenders; - address[] private s_authorizedSendersList; // DEPRECATED, TODO: remove on proxy re-deploy - - /** - * @dev Initializes the contract in active state. - */ - function __AuthorizedOriginReceiver_initialize(bool active) internal onlyInitializing { - s_active = active; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function authorizedReceiverActive() public view virtual override returns (bool) { - return s_active; - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to block unuthorized senders. - * - * Requirements: - * - * - The contract must not be deactive. - */ - function activateAuthorizedReceiver() external validateAuthorizedSenderSetter { - if (authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = true; - emit AuthorizedSendersActive(msg.sender); - } - - /** - * @dev Triggers AuthorizedOriginReceiver usage to allow all senders. - * - * Requirements: - * - * - The contract must be active. - */ - function deactivateAuthorizedReceiver() external validateAuthorizedSenderSetter { - if (!authorizedReceiverActive()) { - revert AlreadySet(); - } - s_active = false; - emit AuthorizedSendersDeactive(msg.sender); - } - - /** - * @notice Sets the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to grant access - */ - function addAuthorizedSenders(address[] calldata senders) external validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.add(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Remove the permission to request for the given wallet(s). - * @param senders The addresses of the wallet addresses to revoke access - */ - function removeAuthorizedSenders(address[] calldata senders) external validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.remove(senders[i]); - } - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() public view returns (address[] memory) { - return EnumerableSet.values(s_authorizedSenders); - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view returns (bool) { - if (!authorizedReceiverActive()) { - return true; - } - return s_authorizedSenders.contains(sender); - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - if (!isAuthorizedSender(tx.origin)) { - revert UnauthorizedSender(); - } - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - if (!_canSetAuthorizedSenders()) { - revert NotAllowedToSetSenders(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedReceiver.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedReceiver.sol deleted file mode 100644 index 52078ff6447..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedReceiver.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {EnumerableSet} from "../../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; -import {AuthorizedReceiverInterface} from "./AuthorizedReceiverInterface.sol"; - -abstract contract AuthorizedReceiver is AuthorizedReceiverInterface { - using EnumerableSet for EnumerableSet.AddressSet; - - event AuthorizedSendersChanged(address[] senders, address changedBy); - - error EmptySendersList(); - error UnauthorizedSender(); - error NotAllowedToSetSenders(); - - EnumerableSet.AddressSet private s_authorizedSenders; - address[] private s_authorizedSendersList; - - /** - * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. - * @param senders The addresses of the authorized Chainlink node - */ - function setAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { - if (senders.length == 0) { - revert EmptySendersList(); - } - for (uint256 i = 0; i < s_authorizedSendersList.length; i++) { - s_authorizedSenders.remove(s_authorizedSendersList[i]); - } - for (uint256 i = 0; i < senders.length; i++) { - s_authorizedSenders.add(senders[i]); - } - s_authorizedSendersList = senders; - emit AuthorizedSendersChanged(senders, msg.sender); - } - - /** - * @notice Retrieve a list of authorized senders - * @return array of addresses - */ - function getAuthorizedSenders() public view override returns (address[] memory) { - return s_authorizedSendersList; - } - - /** - * @notice Use this to check if a node is authorized for fulfilling requests - * @param sender The address of the Chainlink node - * @return The authorization status of the node - */ - function isAuthorizedSender(address sender) public view override returns (bool) { - return s_authorizedSenders.contains(sender); - } - - /** - * @notice customizable guard of who can update the authorized sender list - * @return bool whether sender can update authorized sender list - */ - function _canSetAuthorizedSenders() internal virtual returns (bool); - - /** - * @notice validates the sender is an authorized sender - */ - function _validateIsAuthorizedSender() internal view { - if (!isAuthorizedSender(msg.sender)) { - revert UnauthorizedSender(); - } - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSender() { - _validateIsAuthorizedSender(); - _; - } - - /** - * @notice prevents non-authorized addresses from calling this method - */ - modifier validateAuthorizedSenderSetter() { - if (!_canSetAuthorizedSenders()) { - revert NotAllowedToSetSenders(); - } - _; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/ConfirmedOwnerUpgradeable.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/ConfirmedOwnerUpgradeable.sol deleted file mode 100644 index ebe2e4c14f7..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/ConfirmedOwnerUpgradeable.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {IOwnable} from "../../../../../shared/interfaces/IOwnable.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title The ConfirmedOwnerUpgradeable contract - * @notice An upgrade compatible contract with helpers for basic contract ownership. - */ -contract ConfirmedOwnerUpgradeable is Initializable, IOwnable { - address private s_owner; - address private s_pendingOwner; - - event OwnershipTransferRequested(address indexed from, address indexed to); - event OwnershipTransferred(address indexed from, address indexed to); - - error OwnerMustBeSet(); - error NotProposedOwner(); - error CannotSelfTransfer(); - error OnlyCallableByOwner(); - - /** - * @dev Initializes the contract in unpaused state. - */ - function __ConfirmedOwner_initialize(address newOwner, address pendingOwner) internal onlyInitializing { - if (newOwner == address(0)) { - revert OwnerMustBeSet(); - } - - s_owner = newOwner; - if (pendingOwner != address(0)) { - _transferOwnership(pendingOwner); - } - } - - /** - * @notice Allows an owner to begin transferring ownership to a new address, - * pending. - */ - function transferOwnership(address to) public override onlyOwner { - _transferOwnership(to); - } - - /** - * @notice Allows an ownership transfer to be completed by the recipient. - */ - function acceptOwnership() external override { - if (msg.sender != s_pendingOwner) { - revert NotProposedOwner(); - } - - address oldOwner = s_owner; - s_owner = msg.sender; - s_pendingOwner = address(0); - - emit OwnershipTransferred(oldOwner, msg.sender); - } - - /** - * @notice Get the current owner - */ - function owner() public view override returns (address) { - return s_owner; - } - - /** - * @notice validate, transfer ownership, and emit relevant events - */ - function _transferOwnership(address to) private { - if (to == msg.sender) { - revert CannotSelfTransfer(); - } - - s_pendingOwner = to; - - emit OwnershipTransferRequested(s_owner, to); - } - - /** - * @notice validate access - */ - function _validateOwnership() internal view { - if (msg.sender != s_owner) { - revert OnlyCallableByOwner(); - } - } - - /** - * @notice Reverts if called by anyone other than the contract owner. - */ - modifier onlyOwner() { - _validateOwnership(); - _; - } -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryInterface.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryInterface.sol deleted file mode 100644 index 63044267645..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryInterface.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions billing subscription registry interface. - */ -interface FunctionsBillingRegistryInterface { - struct RequestBilling { - // a unique subscription ID allocated by billing system, - uint64 subscriptionId; - // the client contract that initiated the request to the DON - // to use the subscription it must be added as a consumer on the subscription - address client; - // customer specified gas limit for the fulfillment callback - uint32 gasLimit; - // the expected gas price used to execute the transaction - uint256 gasPrice; - } - - /** - * @notice Get configuration relevant for making requests - * @return uint32 global max for request gas limit - * @return address[] list of registered DONs - */ - function getRequestConfig() external view returns (uint32, address[] memory); - - /** - * @notice Determine the charged fee that will be paid to the Registry owner - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee( - bytes calldata data, - FunctionsBillingRegistryInterface.RequestBilling memory billing - ) external view returns (uint96); - - /** - * @notice Estimate the total cost to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param gasLimit Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasPrice The request's billing configuration - * @param donFee Fee charged by the DON that is paid to Oracle Node - * @param registryFee Fee charged by the DON that is paid to Oracle Node - * @return costEstimate Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) external view returns (uint96); - - /** - * @notice Initiate the billing process for an Functions request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing Billing configuration for the request - * @return requestId - A unique identifier of the request. Can be used to match a request to a response in fulfillRequest. - * @dev Only callable by a node that has been approved on the Registry - */ - function startBilling(bytes calldata data, RequestBilling calldata billing) external returns (bytes32); - - /** - * @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription - * @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment - * @param response response data from DON consensus - * @param err error from DON consensus - * @param transmitter the Oracle who sent the report - * @param signers the Oracles who had a part in generating the report - * @param signerCount the number of signers on the report - * @param reportValidationGas the amount of gas used for the report validation. Cost is split by all fulfillments on the report. - * @param initialGas the initial amount of gas that should be used as a baseline to charge the single fulfillment for execution cost - * @return success - * @dev Only callable by a node that has been approved on the Registry - * @dev simulated offchain to determine if sufficient balance is present to fulfill the request - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, // 31 comes from OCR2Abstract.sol's maxNumOracles constant - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external returns (bool success); - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner(uint64 subscriptionId) external view returns (address owner); -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryMigration.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryMigration.sol deleted file mode 100644 index f9e6649d026..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryMigration.sol +++ /dev/null @@ -1,837 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {LinkTokenInterface} from "../../../../../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../../../../../interfaces/AggregatorV3Interface.sol"; -import {FunctionsBillingRegistryInterface} from "./FunctionsBillingRegistryInterface.sol"; -import {FunctionsOracleInterface} from "./FunctionsOracleInterface.sol"; -import {FunctionsClientInterface} from "./FunctionsClientInterface.sol"; -import {TypeAndVersionInterface} from "../../../../../interfaces/TypeAndVersionInterface.sol"; -import {IERC677Receiver} from "../../../../../shared/interfaces/IERC677Receiver.sol"; -import {AuthorizedOriginReceiverInterface} from "./AuthorizedOriginReceiverInterface.sol"; -import {ConfirmedOwnerUpgradeable} from "./ConfirmedOwnerUpgradeable.sol"; -import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; -import {SafeCast} from "../../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -import {PausableUpgradeable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Billing Registry contract - * @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsBillingRegistryMigration is - Initializable, - ConfirmedOwnerUpgradeable, - PausableUpgradeable, - FunctionsBillingRegistryInterface, - IERC677Receiver, - AuthorizedReceiver -{ - LinkTokenInterface public LINK; - AggregatorV3Interface public LINK_ETH_FEED; - AuthorizedOriginReceiverInterface private ORACLE_WITH_ALLOWLIST; - - // We need to maintain a list of consuming addresses. - // This bound ensures we are able to loop over them as needed. - // Should a user require more consumers, they can use multiple subscriptions. - uint16 public constant MAX_CONSUMERS = 100; - - error TooManyConsumers(); - error InsufficientBalance(); - error InvalidConsumer(uint64 subscriptionId, address consumer); - error InvalidSubscription(); - error OnlyCallableFromLink(); - error InvalidCalldata(); - error MustBeSubOwner(address owner); - error PendingRequestExists(); - error MustBeRequestedOwner(address proposedOwner); - error BalanceInvariantViolated(uint256 internalBalance, uint256 externalBalance); // Should never happen - event FundsRecovered(address to, uint256 amount); - - struct Subscription { - // There are only 1e9*1e18 = 1e27 juels in existence, so the balance can fit in uint96 (2^96 ~ 7e28) - uint96 balance; // Common LINK balance that is controlled by the Registry to be used for all consumer requests. - uint96 blockedBalance; // LINK balance that is reserved to pay for pending consumer requests. - } - // We use the config for the mgmt APIs - struct SubscriptionConfig { - address owner; // Owner can fund/withdraw/cancel the sub. - address requestedOwner; // For safely transferring sub ownership. - // Maintains the list of keys in s_consumers. - // We do this for 2 reasons: - // 1. To be able to clean up all keys from s_consumers when canceling a subscription. - // 2. To be able to return the list of all consumers in getSubscription. - // Note that we need the s_consumers map to be able to directly check if a - // consumer is valid without reading all the consumers from storage. - address[] consumers; - } - // Note a nonce of 0 indicates an the consumer is not assigned to that subscription. - mapping(address => mapping(uint64 => uint64)) /* consumer */ /* subscriptionId */ /* nonce */ private s_consumers; - mapping(uint64 => SubscriptionConfig) /* subscriptionId */ /* subscriptionConfig */ private s_subscriptionConfigs; - mapping(uint64 => Subscription) /* subscriptionId */ /* subscription */ private s_subscriptions; - // We make the sub count public so that its possible to - // get all the current subscriptions via getSubscription. - uint64 private s_currentsubscriptionId; - // s_totalBalance tracks the total link sent to/from - // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. - // A discrepancy with this contract's link balance indicates someone - // sent tokens using transfer and so we may need to use recoverFunds. - uint96 private s_totalBalance; - event SubscriptionCreated(uint64 indexed subscriptionId, address owner); - event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); - event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); - event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); - event SubscriptionCanceled(uint64 indexed subscriptionId, address to, uint256 amount); - event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); - event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); - - error GasLimitTooBig(uint32 have, uint32 want); - error InvalidLinkWeiPrice(int256 linkWei); - error IncorrectRequestID(); - error PaymentTooLarge(); - error Reentrant(); - - mapping(address => uint96) /* oracle node */ /* LINK balance */ private s_withdrawableTokens; - struct Commitment { - uint64 subscriptionId; - address client; - uint32 gasLimit; - uint256 gasPrice; - address don; - uint96 donFee; - uint96 registryFee; - uint96 estimatedCost; - uint256 timestamp; - } - mapping(bytes32 => Commitment) /* requestID */ /* Commitment */ private s_requestCommitments; - event BillingStart(bytes32 indexed requestId, Commitment commitment); - struct ItemizedBill { - uint96 signerPayment; - uint96 transmitterPayment; - uint96 totalCost; - } - event BillingEnd( - bytes32 indexed requestId, - uint64 subscriptionId, - uint96 signerPayment, - uint96 transmitterPayment, - uint96 totalCost, - bool success - ); - event RequestTimedOut(bytes32 indexed requestId); - - struct Config { - // Maxiumum amount of gas that can be given to a request's client callback - uint32 maxGasLimit; - // Reentrancy protection. - bool reentrancyLock; - // stalenessSeconds is how long before we consider the feed price to be stale - // and fallback to fallbackWeiPerUnitLink. - uint32 stalenessSeconds; - // Gas to cover transmitter oracle payment after we calculate the payment. - // We make it configurable in case those operations are repriced. - uint256 gasAfterPaymentCalculation; - // Represents the average gas execution cost. Used in estimating cost beforehand. - uint32 gasOverhead; - // how many seconds it takes before we consider a request to be timed out - uint32 requestTimeoutSeconds; - } - int256 private s_fallbackWeiPerUnitLink; - Config private s_config; - event ConfigSet( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead - ); - - /** - * @dev Initializes the contract. - */ - function initialize(address link, address linkEthFeed, address oracle) public initializer { - __Pausable_init(); - __ConfirmedOwner_initialize(msg.sender, address(0)); - LINK = LinkTokenInterface(link); - LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); - ORACLE_WITH_ALLOWLIST = AuthorizedOriginReceiverInterface(oracle); - } - - /** - * @notice Sets the configuration of the Chainlink Functions billing registry - * @param maxGasLimit global max for request gas limit - * @param stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @param gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @param fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @param gasOverhead average gas execution cost used in estimating total cost - * @param requestTimeoutSeconds e2e timeout after which user won't be charged - */ - function setConfig( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead, - uint32 requestTimeoutSeconds - ) external onlyOwner { - if (fallbackWeiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); - } - s_config = Config({ - maxGasLimit: maxGasLimit, - stalenessSeconds: stalenessSeconds, - gasAfterPaymentCalculation: gasAfterPaymentCalculation, - reentrancyLock: false, - gasOverhead: gasOverhead, - requestTimeoutSeconds: requestTimeoutSeconds - }); - s_fallbackWeiPerUnitLink = fallbackWeiPerUnitLink; - emit ConfigSet(maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, gasOverhead); - } - - /** - * @notice Gets the configuration of the Chainlink Functions billing registry - * @return maxGasLimit global max for request gas limit - * @return stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @return gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @return fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @return gasOverhead average gas execution cost used in estimating total cost - */ - function getConfig() - external - view - returns ( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead - ) - { - return ( - s_config.maxGasLimit, - s_config.stalenessSeconds, - s_config.gasAfterPaymentCalculation, - s_fallbackWeiPerUnitLink, - s_config.gasOverhead - ); - } - - function pause() external onlyOwner { - _pause(); - } - - function unpause() external onlyOwner { - _unpause(); - } - - function getTotalBalance() external view returns (uint256) { - return s_totalBalance; - } - - /** - * @notice Owner cancel subscription, sends remaining link directly to the subscription owner. - * @param subscriptionId subscription id - * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain - */ - function ownerCancelSubscription(uint64 subscriptionId) external onlyOwner { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - cancelSubscriptionHelper(subscriptionId, owner); - } - - /** - * @notice Recover link sent with transfer instead of transferAndCall. - * @param to address to send link to - */ - function recoverFunds(address to) external onlyOwner { - uint256 externalBalance = LINK.balanceOf(address(this)); - uint256 internalBalance = uint256(s_totalBalance); - if (internalBalance > externalBalance) { - revert BalanceInvariantViolated(internalBalance, externalBalance); - } - if (internalBalance < externalBalance) { - uint256 amount = externalBalance - internalBalance; - LINK.transfer(to, amount); - emit FundsRecovered(to, amount); - } - // If the balances are equal, nothing to be done. - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function getRequestConfig() external view override returns (uint32, address[] memory) { - return (s_config.maxGasLimit, getAuthorizedSenders()); - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function getRequiredFee( - bytes calldata /* data */, - FunctionsBillingRegistryInterface.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - return 1; - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) public view override returns (uint96) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - uint256 executionGas = s_config.gasOverhead + s_config.gasAfterPaymentCalculation + gasLimit; - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * gasPrice * executionGas) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - return uint96(paymentNoFee + fee); - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function startBilling( - bytes calldata data, - RequestBilling calldata billing - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (bytes32) { - // Input validation using the subscription storage. - if (s_subscriptionConfigs[billing.subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // It's important to ensure that the consumer is in fact who they say they - // are, otherwise they could use someone else's subscription balance. - // A nonce of 0 indicates consumer is not allocated to the sub. - uint64 currentNonce = s_consumers[billing.client][billing.subscriptionId]; - if (currentNonce == 0) { - revert InvalidConsumer(billing.subscriptionId, billing.client); - } - // No lower bound on the requested gas limit. A user could request 0 - // and they would simply be billed for the gas and computation. - if (billing.gasLimit > s_config.maxGasLimit) { - revert GasLimitTooBig(billing.gasLimit, s_config.maxGasLimit); - } - - // Check that subscription can afford the estimated cost - uint96 oracleFee = FunctionsOracleInterface(msg.sender).getRequiredFee(data, billing); - uint96 registryFee = getRequiredFee(data, billing); - uint96 estimatedCost = estimateCost(billing.gasLimit, billing.gasPrice, oracleFee, registryFee); - uint96 effectiveBalance = s_subscriptions[billing.subscriptionId].balance - - s_subscriptions[billing.subscriptionId].blockedBalance; - if (effectiveBalance < estimatedCost) { - revert InsufficientBalance(); - } - - uint64 nonce = currentNonce + 1; - bytes32 requestId = computeRequestId(msg.sender, billing.client, billing.subscriptionId, nonce); - - Commitment memory commitment = Commitment( - billing.subscriptionId, - billing.client, - billing.gasLimit, - billing.gasPrice, - msg.sender, - oracleFee, - registryFee, - estimatedCost, - block.timestamp - ); - s_requestCommitments[requestId] = commitment; - s_subscriptions[billing.subscriptionId].blockedBalance += estimatedCost; - - emit BillingStart(requestId, commitment); - s_consumers[billing.client][billing.subscriptionId] = nonce; - return requestId; - } - - function computeRequestId( - address don, - address client, - uint64 subscriptionId, - uint64 nonce - ) private pure returns (bytes32) { - return keccak256(abi.encode(don, client, subscriptionId, nonce)); - } - - /** - * @dev calls target address with exactly gasAmount gas and data as calldata - * or reverts if at least gasAmount gas is not available. - */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly - assembly { - let g := gas() - // GAS_FOR_CALL_EXACT_CHECK = 5000 - // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow - // The gas actually passed to the callee is min(gasAmount, 63//64*gas available). - // We want to ensure that we revert if gasAmount > 63//64*gas available - // as we do not want to provide them with less, however that check itself costs - // gas. GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able - // to revert if gasAmount > 63//64*gas available. - if lt(g, 5000) { - revert(0, 0) - } - g := sub(g, 5000) - // if g - g//64 <= gasAmount, revert - // (we subtract g//64 because of EIP-150) - if iszero(gt(sub(g, div(g, 64)), gasAmount)) { - revert(0, 0) - } - // solidity calls check that a contract actually exists at the destination, so we do the same - if iszero(extcodesize(target)) { - revert(0, 0) - } - // call and return whether we succeeded. ignore return data - // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) - success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) - } - return success; - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (bool success) { - Commitment memory commitment = s_requestCommitments[requestId]; - if (commitment.don == address(0)) { - revert IncorrectRequestID(); - } - delete s_requestCommitments[requestId]; - - bytes memory callback = abi.encodeWithSelector( - FunctionsClientInterface.handleOracleFulfillment.selector, - requestId, - response, - err - ); - // Call with explicitly the amount of callback gas requested - // Important to not let them exhaust the gas budget and avoid payment. - // Do not allow any non-view/non-pure coordinator functions to be called - // during the consumers callback code via reentrancyLock. - // NOTE: that callWithExactGas will revert if we do not have sufficient gas - // to give the callee their requested amount. - s_config.reentrancyLock = true; - success = callWithExactGas(commitment.gasLimit, commitment.client, callback); - s_config.reentrancyLock = false; - - // We want to charge users exactly for how much gas they use in their callback. - // The gasAfterPaymentCalculation is meant to cover these additional operations where we - // decrement the subscription balance and increment the oracle's withdrawable balance. - ItemizedBill memory bill = calculatePaymentAmount( - initialGas, - s_config.gasAfterPaymentCalculation, - commitment.donFee, - signerCount, - commitment.registryFee, - reportValidationGas, - tx.gasprice - ); - if (s_subscriptions[commitment.subscriptionId].balance < bill.totalCost) { - revert InsufficientBalance(); - } - s_subscriptions[commitment.subscriptionId].balance -= bill.totalCost; - // Pay out signers their portion of the DON fee - for (uint256 i = 0; i < signerCount; i++) { - if (signers[i] != transmitter) { - s_withdrawableTokens[signers[i]] += bill.signerPayment; - } - } - // Pay out the registry fee - s_withdrawableTokens[owner()] += commitment.registryFee; - // Reimburse the transmitter for the execution gas cost + pay them their portion of the DON fee - s_withdrawableTokens[transmitter] += bill.transmitterPayment; - // Remove blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Include payment in the event for tracking costs. - emit BillingEnd( - requestId, - commitment.subscriptionId, - bill.signerPayment, - bill.transmitterPayment, - bill.totalCost, - success - ); - } - - // Determine the cost breakdown for payment - function calculatePaymentAmount( - uint256 startGas, - uint256 gasAfterPaymentCalculation, - uint96 donFee, - uint8 signerCount, - uint96 registryFee, - uint256 reportValidationGas, - uint256 weiPerUnitGas - ) private view returns (ItemizedBill memory) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * - weiPerUnitGas * - (reportValidationGas + gasAfterPaymentCalculation + startGas - gasleft())) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - uint96 signerPayment = donFee / uint96(signerCount); - uint96 transmitterPayment = uint96(paymentNoFee) + signerPayment; - uint96 totalCost = SafeCast.toUint96(paymentNoFee + fee); - return ItemizedBill(signerPayment, transmitterPayment, totalCost); - } - - function getFeedData() private view returns (int256) { - uint32 stalenessSeconds = s_config.stalenessSeconds; - bool staleFallback = stalenessSeconds > 0; - (, int256 weiPerUnitLink, , uint256 timestamp, ) = LINK_ETH_FEED.latestRoundData(); - // solhint-disable-next-line not-rely-on-time - if (staleFallback && stalenessSeconds < block.timestamp - timestamp) { - weiPerUnitLink = s_fallbackWeiPerUnitLink; - } - return weiPerUnitLink; - } - - /* - * @notice Oracle withdraw LINK earned through fulfilling requests - * @notice If amount is 0 the full balance will be withdrawn - * @param recipient where to send the funds - * @param amount amount to withdraw - */ - function oracleWithdraw(address recipient, uint96 amount) external nonReentrant whenNotPaused { - if (amount == 0) { - amount = s_withdrawableTokens[msg.sender]; - } - if (s_withdrawableTokens[msg.sender] < amount) { - revert InsufficientBalance(); - } - s_withdrawableTokens[msg.sender] -= amount; - s_totalBalance -= amount; - if (!LINK.transfer(recipient, amount)) { - revert InsufficientBalance(); - } - } - - function onTokenTransfer( - address /* sender */, - uint256 amount, - bytes calldata data - ) external override nonReentrant whenNotPaused { - if (msg.sender != address(LINK)) { - revert OnlyCallableFromLink(); - } - if (data.length != 32) { - revert InvalidCalldata(); - } - uint64 subscriptionId = abi.decode(data, (uint64)); - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // We do not check that the msg.sender is the subscription owner, - // anyone can fund a subscription. - uint256 oldBalance = s_subscriptions[subscriptionId].balance; - s_subscriptions[subscriptionId].balance += uint96(amount); - s_totalBalance += uint96(amount); - emit SubscriptionFunded(subscriptionId, oldBalance, oldBalance + amount); - } - - function getCurrentsubscriptionId() external view returns (uint64) { - return s_currentsubscriptionId; - } - - /** - * @notice Get details about a subscription. - * @param subscriptionId - ID of the subscription - * @return balance - LINK balance of the subscription in juels. - * @return owner - owner of the subscription. - * @return consumers - list of consumer address which are able to use this subscription. - */ - function getSubscription( - uint64 subscriptionId - ) external view returns (uint96 balance, address owner, address[] memory consumers) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return ( - s_subscriptions[subscriptionId].balance, - s_subscriptionConfigs[subscriptionId].owner, - s_subscriptionConfigs[subscriptionId].consumers - ); - } - - /** - * @notice Create a new subscription. - * @return subscriptionId - A unique subscription id. - * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - * @dev Note to fund the subscription, use transferAndCall. For example - * @dev LINKTOKEN.transferAndCall( - * @dev address(REGISTRY), - * @dev amount, - * @dev abi.encode(subscriptionId)); - */ - function createSubscription() external nonReentrant whenNotPaused onlyAuthorizedUsers returns (uint64) { - s_currentsubscriptionId++; - uint64 currentsubscriptionId = s_currentsubscriptionId; - address[] memory consumers = new address[](0); - s_subscriptions[currentsubscriptionId] = Subscription({balance: 0, blockedBalance: 0}); - s_subscriptionConfigs[currentsubscriptionId] = SubscriptionConfig({ - owner: msg.sender, - requestedOwner: address(0), - consumers: consumers - }); - - emit SubscriptionCreated(currentsubscriptionId, msg.sender); - return currentsubscriptionId; - } - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner(uint64 subscriptionId) external view override returns (address owner) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return s_subscriptionConfigs[subscriptionId].owner; - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @param newOwner - proposed new owner of the subscription - */ - function requestSubscriptionOwnerTransfer( - uint64 subscriptionId, - address newOwner - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Proposing to address(0) would never be claimable so don't need to check. - if (s_subscriptionConfigs[subscriptionId].requestedOwner != newOwner) { - s_subscriptionConfigs[subscriptionId].requestedOwner = newOwner; - emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); - } - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @dev will revert if original owner of subscriptionId has - * not requested that msg.sender become the new owner. - */ - function acceptSubscriptionOwnerTransfer( - uint64 subscriptionId - ) external nonReentrant whenNotPaused onlyAuthorizedUsers { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - if (s_subscriptionConfigs[subscriptionId].requestedOwner != msg.sender) { - revert MustBeRequestedOwner(s_subscriptionConfigs[subscriptionId].requestedOwner); - } - address oldOwner = s_subscriptionConfigs[subscriptionId].owner; - s_subscriptionConfigs[subscriptionId].owner = msg.sender; - s_subscriptionConfigs[subscriptionId].requestedOwner = address(0); - emit SubscriptionOwnerTransferred(subscriptionId, oldOwner, msg.sender); - } - - /** - * @notice Remove a consumer from a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - Consumer to remove from the subscription - */ - function removeConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (s_consumers[consumer][subscriptionId] == 0) { - revert InvalidConsumer(subscriptionId, consumer); - } - // Note bounded by MAX_CONSUMERS - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - uint256 lastConsumerIndex = consumers.length - 1; - for (uint256 i = 0; i < consumers.length; i++) { - if (consumers[i] == consumer) { - address last = consumers[lastConsumerIndex]; - // Storage write to preserve last element - s_subscriptionConfigs[subscriptionId].consumers[i] = last; - // Storage remove last element - s_subscriptionConfigs[subscriptionId].consumers.pop(); - break; - } - } - delete s_consumers[consumer][subscriptionId]; - emit SubscriptionConsumerRemoved(subscriptionId, consumer); - } - - /** - * @notice Add a consumer to a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - New consumer which can use the subscription - */ - function addConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Already maxed, cannot add any more consumers. - if (s_subscriptionConfigs[subscriptionId].consumers.length == MAX_CONSUMERS) { - revert TooManyConsumers(); - } - if (s_consumers[consumer][subscriptionId] != 0) { - // Idempotence - do nothing if already added. - // Ensures uniqueness in s_subscriptions[subscriptionId].consumers. - return; - } - // Initialize the nonce to 1, indicating the consumer is allocated. - s_consumers[consumer][subscriptionId] = 1; - s_subscriptionConfigs[subscriptionId].consumers.push(consumer); - - emit SubscriptionConsumerAdded(subscriptionId, consumer); - } - - /** - * @notice Cancel a subscription - * @param subscriptionId - ID of the subscription - * @param to - Where to send the remaining LINK to - */ - function cancelSubscription( - uint64 subscriptionId, - address to - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (pendingRequestExists(subscriptionId)) { - revert PendingRequestExists(); - } - cancelSubscriptionHelper(subscriptionId, to); - } - - function cancelSubscriptionHelper(uint64 subscriptionId, address to) private nonReentrant { - SubscriptionConfig memory subConfig = s_subscriptionConfigs[subscriptionId]; - uint96 balance = s_subscriptions[subscriptionId].balance; - // Note bounded by MAX_CONSUMERS; - // If no consumers, does nothing. - for (uint256 i = 0; i < subConfig.consumers.length; i++) { - delete s_consumers[subConfig.consumers[i]][subscriptionId]; - } - delete s_subscriptionConfigs[subscriptionId]; - delete s_subscriptions[subscriptionId]; - s_totalBalance -= balance; - if (!LINK.transfer(to, uint256(balance))) { - revert InsufficientBalance(); - } - emit SubscriptionCanceled(subscriptionId, to, balance); - } - - /** - * @notice Check to see if there exists a request commitment for all consumers for a given sub. - * @param subscriptionId - ID of the subscription - * @return true if there exists at least one unfulfilled request for the subscription, false - * otherwise. - * @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). - * @dev Used to disable subscription canceling while outstanding request are present. - */ - - function pendingRequestExists(uint64 subscriptionId) public view returns (bool) { - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - address[] memory authorizedSendersList = getAuthorizedSenders(); - for (uint256 i = 0; i < consumers.length; i++) { - for (uint256 j = 0; j < authorizedSendersList.length; j++) { - bytes32 requestId = computeRequestId( - authorizedSendersList[j], - consumers[i], - subscriptionId, - s_consumers[consumers[i]][subscriptionId] - ); - if (s_requestCommitments[requestId].don != address(0)) { - return true; - } - } - } - return false; - } - - /** - * @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled - * @param requestIdsToTimeout - A list of request IDs to time out - */ - - function timeoutRequests(bytes32[] calldata requestIdsToTimeout) external whenNotPaused { - for (uint256 i = 0; i < requestIdsToTimeout.length; i++) { - bytes32 requestId = requestIdsToTimeout[i]; - Commitment memory commitment = s_requestCommitments[requestId]; - - // Check that the message sender is the subscription owner - if (msg.sender != s_subscriptionConfigs[commitment.subscriptionId].owner) { - revert MustBeSubOwner(s_subscriptionConfigs[commitment.subscriptionId].owner); - } - - if (commitment.timestamp + s_config.requestTimeoutSeconds > block.timestamp) { - // Decrement blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Delete commitment - delete s_requestCommitments[requestId]; - emit RequestTimedOut(requestId); - } - } - } - - /** - * @dev The allow list is kept on the Oracle contract. This modifier checks if a user is authorized from there. - */ - modifier onlyAuthorizedUsers() { - if (ORACLE_WITH_ALLOWLIST.authorizedReceiverActive() && !ORACLE_WITH_ALLOWLIST.isAuthorizedSender(msg.sender)) { - revert UnauthorizedSender(); - } - _; - } - - modifier onlySubOwner(uint64 subscriptionId) { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - if (msg.sender != owner) { - revert MustBeSubOwner(owner); - } - _; - } - - modifier nonReentrant() { - if (s_config.reentrancyLock) { - revert Reentrant(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override onlyOwner returns (bool) { - return true; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryOriginal.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryOriginal.sol deleted file mode 100644 index 39bff270401..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryOriginal.sol +++ /dev/null @@ -1,837 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {LinkTokenInterface} from "../../../../../shared/interfaces/LinkTokenInterface.sol"; -import {AggregatorV3Interface} from "../../../../../interfaces/AggregatorV3Interface.sol"; -import {FunctionsOracleInterface} from "./FunctionsOracleInterface.sol"; -import {FunctionsBillingRegistryInterface} from "./FunctionsBillingRegistryInterface.sol"; -import {FunctionsClientInterface} from "./FunctionsClientInterface.sol"; -import {TypeAndVersionInterface} from "../../../../../interfaces/TypeAndVersionInterface.sol"; -import {IERC677Receiver} from "../../../../../shared/interfaces/IERC677Receiver.sol"; -import {AuthorizedOriginReceiverInterface} from "./AuthorizedOriginReceiverInterface.sol"; -import {ConfirmedOwnerUpgradeable} from "./ConfirmedOwnerUpgradeable.sol"; -import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; -import {SafeCast} from "../../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; -import {PausableUpgradeable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Billing Registry contract - * @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsBillingRegistryOriginal is - Initializable, - ConfirmedOwnerUpgradeable, - PausableUpgradeable, - FunctionsBillingRegistryInterface, - IERC677Receiver, - AuthorizedReceiver -{ - LinkTokenInterface public LINK; - AggregatorV3Interface public LINK_ETH_FEED; - AuthorizedOriginReceiverInterface private ORACLE_WITH_ALLOWLIST; - - // We need to maintain a list of consuming addresses. - // This bound ensures we are able to loop over them as needed. - // Should a user require more consumers, they can use multiple subscriptions. - uint16 public constant MAX_CONSUMERS = 100; - - error TooManyConsumers(); - error InsufficientBalance(); - error InvalidConsumer(uint64 subscriptionId, address consumer); - error InvalidSubscription(); - error OnlyCallableFromLink(); - error InvalidCalldata(); - error MustBeSubOwner(address owner); - error PendingRequestExists(); - error MustBeRequestedOwner(address proposedOwner); - error BalanceInvariantViolated(uint256 internalBalance, uint256 externalBalance); // Should never happen - event FundsRecovered(address to, uint256 amount); - - struct Subscription { - // There are only 1e9*1e18 = 1e27 juels in existence, so the balance can fit in uint96 (2^96 ~ 7e28) - uint96 balance; // Common LINK balance that is controlled by the Registry to be used for all consumer requests. - uint96 blockedBalance; // LINK balance that is reserved to pay for pending consumer requests. - } - // We use the config for the mgmt APIs - struct SubscriptionConfig { - address owner; // Owner can fund/withdraw/cancel the sub. - address requestedOwner; // For safely transferring sub ownership. - // Maintains the list of keys in s_consumers. - // We do this for 2 reasons: - // 1. To be able to clean up all keys from s_consumers when canceling a subscription. - // 2. To be able to return the list of all consumers in getSubscription. - // Note that we need the s_consumers map to be able to directly check if a - // consumer is valid without reading all the consumers from storage. - address[] consumers; - } - // Note a nonce of 0 indicates an the consumer is not assigned to that subscription. - mapping(address => mapping(uint64 => uint64)) /* consumer */ /* subscriptionId */ /* nonce */ private s_consumers; - mapping(uint64 => SubscriptionConfig) /* subscriptionId */ /* subscriptionConfig */ private s_subscriptionConfigs; - mapping(uint64 => Subscription) /* subscriptionId */ /* subscription */ private s_subscriptions; - // We make the sub count public so that its possible to - // get all the current subscriptions via getSubscription. - uint64 private s_currentsubscriptionId; - // s_totalBalance tracks the total link sent to/from - // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. - // A discrepancy with this contract's link balance indicates someone - // sent tokens using transfer and so we may need to use recoverFunds. - uint96 private s_totalBalance; - event SubscriptionCreated(uint64 indexed subscriptionId, address owner); - event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); - event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); - event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); - event SubscriptionCanceled(uint64 indexed subscriptionId, address to, uint256 amount); - event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); - event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); - - error GasLimitTooBig(uint32 have, uint32 want); - error InvalidLinkWeiPrice(int256 linkWei); - error IncorrectRequestID(); - error PaymentTooLarge(); - error Reentrant(); - - mapping(address => uint96) /* oracle node */ /* LINK balance */ private s_withdrawableTokens; - struct Commitment { - uint64 subscriptionId; - address client; - uint32 gasLimit; - uint256 gasPrice; - address don; - uint96 donFee; - uint96 registryFee; - uint96 estimatedCost; - uint256 timestamp; - } - mapping(bytes32 => Commitment) /* requestID */ /* Commitment */ private s_requestCommitments; - event BillingStart(bytes32 indexed requestId, Commitment commitment); - struct ItemizedBill { - uint96 signerPayment; - uint96 transmitterPayment; - uint96 totalCost; - } - event BillingEnd( - bytes32 indexed requestId, - uint64 subscriptionId, - uint96 signerPayment, - uint96 transmitterPayment, - uint96 totalCost, - bool success - ); - event RequestTimedOut(bytes32 indexed requestId); - - struct Config { - // Maxiumum amount of gas that can be given to a request's client callback - uint32 maxGasLimit; - // Reentrancy protection. - bool reentrancyLock; - // stalenessSeconds is how long before we consider the feed price to be stale - // and fallback to fallbackWeiPerUnitLink. - uint32 stalenessSeconds; - // Gas to cover transmitter oracle payment after we calculate the payment. - // We make it configurable in case those operations are repriced. - uint256 gasAfterPaymentCalculation; - // Represents the average gas execution cost. Used in estimating cost beforehand. - uint32 gasOverhead; - // how many seconds it takes before we consider a request to be timed out - uint32 requestTimeoutSeconds; - } - int256 private s_fallbackWeiPerUnitLink; - Config private s_config; - event ConfigSet( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead - ); - - /** - * @dev Initializes the contract. - */ - function initialize(address link, address linkEthFeed, address oracle) public initializer { - __Pausable_init(); - __ConfirmedOwner_initialize(msg.sender, address(0)); - LINK = LinkTokenInterface(link); - LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); - ORACLE_WITH_ALLOWLIST = AuthorizedOriginReceiverInterface(oracle); - } - - /** - * @notice Sets the configuration of the Chainlink Functions billing registry - * @param maxGasLimit global max for request gas limit - * @param stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @param gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @param fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @param gasOverhead average gas execution cost used in estimating total cost - * @param requestTimeoutSeconds e2e timeout after which user won't be charged - */ - function setConfig( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead, - uint32 requestTimeoutSeconds - ) external onlyOwner { - if (fallbackWeiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); - } - s_config = Config({ - maxGasLimit: maxGasLimit, - stalenessSeconds: stalenessSeconds, - gasAfterPaymentCalculation: gasAfterPaymentCalculation, - reentrancyLock: false, - gasOverhead: gasOverhead, - requestTimeoutSeconds: requestTimeoutSeconds - }); - s_fallbackWeiPerUnitLink = fallbackWeiPerUnitLink; - emit ConfigSet(maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, gasOverhead); - } - - /** - * @notice Gets the configuration of the Chainlink Functions billing registry - * @return maxGasLimit global max for request gas limit - * @return stalenessSeconds if the eth/link feed is more stale then this, use the fallback price - * @return gasAfterPaymentCalculation gas used in doing accounting after completing the gas measurement - * @return fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed - * @return gasOverhead average gas execution cost used in estimating total cost - */ - function getConfig() - external - view - returns ( - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint256 gasAfterPaymentCalculation, - int256 fallbackWeiPerUnitLink, - uint32 gasOverhead - ) - { - return ( - s_config.maxGasLimit, - s_config.stalenessSeconds, - s_config.gasAfterPaymentCalculation, - s_fallbackWeiPerUnitLink, - s_config.gasOverhead - ); - } - - function pause() external onlyOwner { - _pause(); - } - - function unpause() external onlyOwner { - _unpause(); - } - - function getTotalBalance() external view returns (uint256) { - return s_totalBalance; - } - - /** - * @notice Owner cancel subscription, sends remaining link directly to the subscription owner. - * @param subscriptionId subscription id - * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain - */ - function ownerCancelSubscription(uint64 subscriptionId) external onlyOwner { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - cancelSubscriptionHelper(subscriptionId, owner); - } - - /** - * @notice Recover link sent with transfer instead of transferAndCall. - * @param to address to send link to - */ - function recoverFunds(address to) external onlyOwner { - uint256 externalBalance = LINK.balanceOf(address(this)); - uint256 internalBalance = uint256(s_totalBalance); - if (internalBalance > externalBalance) { - revert BalanceInvariantViolated(internalBalance, externalBalance); - } - if (internalBalance < externalBalance) { - uint256 amount = externalBalance - internalBalance; - LINK.transfer(to, amount); - emit FundsRecovered(to, amount); - } - // If the balances are equal, nothing to be done. - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function getRequestConfig() external view override returns (uint32, address[] memory) { - return (s_config.maxGasLimit, getAuthorizedSenders()); - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function getRequiredFee( - bytes calldata /* data */, - FunctionsBillingRegistryInterface.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - return 0; - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) public view override returns (uint96) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - uint256 executionGas = s_config.gasOverhead + s_config.gasAfterPaymentCalculation + gasLimit; - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * gasPrice * executionGas) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - return uint96(paymentNoFee + fee); - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function startBilling( - bytes calldata data, - RequestBilling calldata billing - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (bytes32) { - // Input validation using the subscription storage. - if (s_subscriptionConfigs[billing.subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // It's important to ensure that the consumer is in fact who they say they - // are, otherwise they could use someone else's subscription balance. - // A nonce of 0 indicates consumer is not allocated to the sub. - uint64 currentNonce = s_consumers[billing.client][billing.subscriptionId]; - if (currentNonce == 0) { - revert InvalidConsumer(billing.subscriptionId, billing.client); - } - // No lower bound on the requested gas limit. A user could request 0 - // and they would simply be billed for the gas and computation. - if (billing.gasLimit > s_config.maxGasLimit) { - revert GasLimitTooBig(billing.gasLimit, s_config.maxGasLimit); - } - - // Check that subscription can afford the estimated cost - uint96 oracleFee = FunctionsOracleInterface(msg.sender).getRequiredFee(data, billing); - uint96 registryFee = getRequiredFee(data, billing); - uint96 estimatedCost = estimateCost(billing.gasLimit, billing.gasPrice, oracleFee, registryFee); - uint96 effectiveBalance = s_subscriptions[billing.subscriptionId].balance - - s_subscriptions[billing.subscriptionId].blockedBalance; - if (effectiveBalance < estimatedCost) { - revert InsufficientBalance(); - } - - uint64 nonce = currentNonce + 1; - bytes32 requestId = computeRequestId(msg.sender, billing.client, billing.subscriptionId, nonce); - - Commitment memory commitment = Commitment( - billing.subscriptionId, - billing.client, - billing.gasLimit, - billing.gasPrice, - msg.sender, - oracleFee, - registryFee, - estimatedCost, - block.timestamp - ); - s_requestCommitments[requestId] = commitment; - s_subscriptions[billing.subscriptionId].blockedBalance += estimatedCost; - - emit BillingStart(requestId, commitment); - s_consumers[billing.client][billing.subscriptionId] = nonce; - return requestId; - } - - function computeRequestId( - address don, - address client, - uint64 subscriptionId, - uint64 nonce - ) private pure returns (bytes32) { - return keccak256(abi.encode(don, client, subscriptionId, nonce)); - } - - /** - * @dev calls target address with exactly gasAmount gas and data as calldata - * or reverts if at least gasAmount gas is not available. - */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly - assembly { - let g := gas() - // GAS_FOR_CALL_EXACT_CHECK = 5000 - // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow - // The gas actually passed to the callee is min(gasAmount, 63//64*gas available). - // We want to ensure that we revert if gasAmount > 63//64*gas available - // as we do not want to provide them with less, however that check itself costs - // gas. GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able - // to revert if gasAmount > 63//64*gas available. - if lt(g, 5000) { - revert(0, 0) - } - g := sub(g, 5000) - // if g - g//64 <= gasAmount, revert - // (we subtract g//64 because of EIP-150) - if iszero(gt(sub(g, div(g, 64)), gasAmount)) { - revert(0, 0) - } - // solidity calls check that a contract actually exists at the destination, so we do the same - if iszero(extcodesize(target)) { - revert(0, 0) - } - // call and return whether we succeeded. ignore return data - // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) - success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) - } - return success; - } - - /** - * @inheritdoc FunctionsBillingRegistryInterface - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external override validateAuthorizedSender nonReentrant whenNotPaused returns (bool success) { - Commitment memory commitment = s_requestCommitments[requestId]; - if (commitment.don == address(0)) { - revert IncorrectRequestID(); - } - delete s_requestCommitments[requestId]; - - bytes memory callback = abi.encodeWithSelector( - FunctionsClientInterface.handleOracleFulfillment.selector, - requestId, - response, - err - ); - // Call with explicitly the amount of callback gas requested - // Important to not let them exhaust the gas budget and avoid payment. - // Do not allow any non-view/non-pure coordinator functions to be called - // during the consumers callback code via reentrancyLock. - // NOTE: that callWithExactGas will revert if we do not have sufficient gas - // to give the callee their requested amount. - s_config.reentrancyLock = true; - success = callWithExactGas(commitment.gasLimit, commitment.client, callback); - s_config.reentrancyLock = false; - - // We want to charge users exactly for how much gas they use in their callback. - // The gasAfterPaymentCalculation is meant to cover these additional operations where we - // decrement the subscription balance and increment the oracle's withdrawable balance. - ItemizedBill memory bill = calculatePaymentAmount( - initialGas, - s_config.gasAfterPaymentCalculation, - commitment.donFee, - signerCount, - commitment.registryFee, - reportValidationGas, - tx.gasprice - ); - if (s_subscriptions[commitment.subscriptionId].balance < bill.totalCost) { - revert InsufficientBalance(); - } - s_subscriptions[commitment.subscriptionId].balance -= bill.totalCost; - // Pay out signers their portion of the DON fee - for (uint256 i = 0; i < signerCount; i++) { - if (signers[i] != transmitter) { - s_withdrawableTokens[signers[i]] += bill.signerPayment; - } - } - // Pay out the registry fee - s_withdrawableTokens[owner()] += commitment.registryFee; - // Reimburse the transmitter for the execution gas cost + pay them their portion of the DON fee - s_withdrawableTokens[transmitter] += bill.transmitterPayment; - // Remove blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Include payment in the event for tracking costs. - emit BillingEnd( - requestId, - commitment.subscriptionId, - bill.signerPayment, - bill.transmitterPayment, - bill.totalCost, - success - ); - } - - // Determine the cost breakdown for payment - function calculatePaymentAmount( - uint256 startGas, - uint256 gasAfterPaymentCalculation, - uint96 donFee, - uint8 signerCount, - uint96 registryFee, - uint256 reportValidationGas, - uint256 weiPerUnitGas - ) private view returns (ItemizedBill memory) { - int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); - if (weiPerUnitLink <= 0) { - revert InvalidLinkWeiPrice(weiPerUnitLink); - } - // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels - uint256 paymentNoFee = (1e18 * - weiPerUnitGas * - (reportValidationGas + gasAfterPaymentCalculation + startGas - gasleft())) / uint256(weiPerUnitLink); - uint256 fee = uint256(donFee) + uint256(registryFee); - if (paymentNoFee > (1e27 - fee)) { - revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. - } - uint96 signerPayment = donFee / uint96(signerCount); - uint96 transmitterPayment = uint96(paymentNoFee) + signerPayment; - uint96 totalCost = SafeCast.toUint96(paymentNoFee + fee); - return ItemizedBill(signerPayment, transmitterPayment, totalCost); - } - - function getFeedData() private view returns (int256) { - uint32 stalenessSeconds = s_config.stalenessSeconds; - bool staleFallback = stalenessSeconds > 0; - (, int256 weiPerUnitLink, , uint256 timestamp, ) = LINK_ETH_FEED.latestRoundData(); - // solhint-disable-next-line not-rely-on-time - if (staleFallback && stalenessSeconds < block.timestamp - timestamp) { - weiPerUnitLink = s_fallbackWeiPerUnitLink; - } - return weiPerUnitLink; - } - - /* - * @notice Oracle withdraw LINK earned through fulfilling requests - * @notice If amount is 0 the full balance will be withdrawn - * @param recipient where to send the funds - * @param amount amount to withdraw - */ - function oracleWithdraw(address recipient, uint96 amount) external nonReentrant whenNotPaused { - if (amount == 0) { - amount = s_withdrawableTokens[msg.sender]; - } - if (s_withdrawableTokens[msg.sender] < amount) { - revert InsufficientBalance(); - } - s_withdrawableTokens[msg.sender] -= amount; - s_totalBalance -= amount; - if (!LINK.transfer(recipient, amount)) { - revert InsufficientBalance(); - } - } - - function onTokenTransfer( - address /* sender */, - uint256 amount, - bytes calldata data - ) external override nonReentrant whenNotPaused { - if (msg.sender != address(LINK)) { - revert OnlyCallableFromLink(); - } - if (data.length != 32) { - revert InvalidCalldata(); - } - uint64 subscriptionId = abi.decode(data, (uint64)); - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - // We do not check that the msg.sender is the subscription owner, - // anyone can fund a subscription. - uint256 oldBalance = s_subscriptions[subscriptionId].balance; - s_subscriptions[subscriptionId].balance += uint96(amount); - s_totalBalance += uint96(amount); - emit SubscriptionFunded(subscriptionId, oldBalance, oldBalance + amount); - } - - function getCurrentsubscriptionId() external view returns (uint64) { - return s_currentsubscriptionId; - } - - /** - * @notice Get details about a subscription. - * @param subscriptionId - ID of the subscription - * @return balance - LINK balance of the subscription in juels. - * @return owner - owner of the subscription. - * @return consumers - list of consumer address which are able to use this subscription. - */ - function getSubscription( - uint64 subscriptionId - ) external view returns (uint96 balance, address owner, address[] memory consumers) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return ( - s_subscriptions[subscriptionId].balance, - s_subscriptionConfigs[subscriptionId].owner, - s_subscriptionConfigs[subscriptionId].consumers - ); - } - - /** - * @notice Create a new subscription. - * @return subscriptionId - A unique subscription id. - * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. - * @dev Note to fund the subscription, use transferAndCall. For example - * @dev LINKTOKEN.transferAndCall( - * @dev address(REGISTRY), - * @dev amount, - * @dev abi.encode(subscriptionId)); - */ - function createSubscription() external nonReentrant whenNotPaused onlyAuthorizedUsers returns (uint64) { - s_currentsubscriptionId++; - uint64 currentsubscriptionId = s_currentsubscriptionId; - address[] memory consumers = new address[](0); - s_subscriptions[currentsubscriptionId] = Subscription({balance: 0, blockedBalance: 0}); - s_subscriptionConfigs[currentsubscriptionId] = SubscriptionConfig({ - owner: msg.sender, - requestedOwner: address(0), - consumers: consumers - }); - - emit SubscriptionCreated(currentsubscriptionId, msg.sender); - return currentsubscriptionId; - } - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner(uint64 subscriptionId) external view override returns (address owner) { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - return s_subscriptionConfigs[subscriptionId].owner; - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @param newOwner - proposed new owner of the subscription - */ - function requestSubscriptionOwnerTransfer( - uint64 subscriptionId, - address newOwner - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Proposing to address(0) would never be claimable so don't need to check. - if (s_subscriptionConfigs[subscriptionId].requestedOwner != newOwner) { - s_subscriptionConfigs[subscriptionId].requestedOwner = newOwner; - emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); - } - } - - /** - * @notice Request subscription owner transfer. - * @param subscriptionId - ID of the subscription - * @dev will revert if original owner of subscriptionId has - * not requested that msg.sender become the new owner. - */ - function acceptSubscriptionOwnerTransfer( - uint64 subscriptionId - ) external nonReentrant whenNotPaused onlyAuthorizedUsers { - if (s_subscriptionConfigs[subscriptionId].owner == address(0)) { - revert InvalidSubscription(); - } - if (s_subscriptionConfigs[subscriptionId].requestedOwner != msg.sender) { - revert MustBeRequestedOwner(s_subscriptionConfigs[subscriptionId].requestedOwner); - } - address oldOwner = s_subscriptionConfigs[subscriptionId].owner; - s_subscriptionConfigs[subscriptionId].owner = msg.sender; - s_subscriptionConfigs[subscriptionId].requestedOwner = address(0); - emit SubscriptionOwnerTransferred(subscriptionId, oldOwner, msg.sender); - } - - /** - * @notice Remove a consumer from a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - Consumer to remove from the subscription - */ - function removeConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (s_consumers[consumer][subscriptionId] == 0) { - revert InvalidConsumer(subscriptionId, consumer); - } - // Note bounded by MAX_CONSUMERS - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - uint256 lastConsumerIndex = consumers.length - 1; - for (uint256 i = 0; i < consumers.length; i++) { - if (consumers[i] == consumer) { - address last = consumers[lastConsumerIndex]; - // Storage write to preserve last element - s_subscriptionConfigs[subscriptionId].consumers[i] = last; - // Storage remove last element - s_subscriptionConfigs[subscriptionId].consumers.pop(); - break; - } - } - delete s_consumers[consumer][subscriptionId]; - emit SubscriptionConsumerRemoved(subscriptionId, consumer); - } - - /** - * @notice Add a consumer to a Chainlink Functions subscription. - * @param subscriptionId - ID of the subscription - * @param consumer - New consumer which can use the subscription - */ - function addConsumer( - uint64 subscriptionId, - address consumer - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - // Already maxed, cannot add any more consumers. - if (s_subscriptionConfigs[subscriptionId].consumers.length == MAX_CONSUMERS) { - revert TooManyConsumers(); - } - if (s_consumers[consumer][subscriptionId] != 0) { - // Idempotence - do nothing if already added. - // Ensures uniqueness in s_subscriptions[subscriptionId].consumers. - return; - } - // Initialize the nonce to 1, indicating the consumer is allocated. - s_consumers[consumer][subscriptionId] = 1; - s_subscriptionConfigs[subscriptionId].consumers.push(consumer); - - emit SubscriptionConsumerAdded(subscriptionId, consumer); - } - - /** - * @notice Cancel a subscription - * @param subscriptionId - ID of the subscription - * @param to - Where to send the remaining LINK to - */ - function cancelSubscription( - uint64 subscriptionId, - address to - ) external onlySubOwner(subscriptionId) nonReentrant whenNotPaused { - if (pendingRequestExists(subscriptionId)) { - revert PendingRequestExists(); - } - cancelSubscriptionHelper(subscriptionId, to); - } - - function cancelSubscriptionHelper(uint64 subscriptionId, address to) private nonReentrant { - SubscriptionConfig memory subConfig = s_subscriptionConfigs[subscriptionId]; - uint96 balance = s_subscriptions[subscriptionId].balance; - // Note bounded by MAX_CONSUMERS; - // If no consumers, does nothing. - for (uint256 i = 0; i < subConfig.consumers.length; i++) { - delete s_consumers[subConfig.consumers[i]][subscriptionId]; - } - delete s_subscriptionConfigs[subscriptionId]; - delete s_subscriptions[subscriptionId]; - s_totalBalance -= balance; - if (!LINK.transfer(to, uint256(balance))) { - revert InsufficientBalance(); - } - emit SubscriptionCanceled(subscriptionId, to, balance); - } - - /** - * @notice Check to see if there exists a request commitment for all consumers for a given sub. - * @param subscriptionId - ID of the subscription - * @return true if there exists at least one unfulfilled request for the subscription, false - * otherwise. - * @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). - * @dev Used to disable subscription canceling while outstanding request are present. - */ - - function pendingRequestExists(uint64 subscriptionId) public view returns (bool) { - address[] memory consumers = s_subscriptionConfigs[subscriptionId].consumers; - address[] memory authorizedSendersList = getAuthorizedSenders(); - for (uint256 i = 0; i < consumers.length; i++) { - for (uint256 j = 0; j < authorizedSendersList.length; j++) { - bytes32 requestId = computeRequestId( - authorizedSendersList[j], - consumers[i], - subscriptionId, - s_consumers[consumers[i]][subscriptionId] - ); - if (s_requestCommitments[requestId].don != address(0)) { - return true; - } - } - } - return false; - } - - /** - * @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled - * @param requestIdsToTimeout - A list of request IDs to time out - */ - - function timeoutRequests(bytes32[] calldata requestIdsToTimeout) external whenNotPaused { - for (uint256 i = 0; i < requestIdsToTimeout.length; i++) { - bytes32 requestId = requestIdsToTimeout[i]; - Commitment memory commitment = s_requestCommitments[requestId]; - - // Check that the message sender is the subscription owner - if (msg.sender != s_subscriptionConfigs[commitment.subscriptionId].owner) { - revert MustBeSubOwner(s_subscriptionConfigs[commitment.subscriptionId].owner); - } - - if (commitment.timestamp + s_config.requestTimeoutSeconds > block.timestamp) { - // Decrement blocked balance - s_subscriptions[commitment.subscriptionId].blockedBalance -= commitment.estimatedCost; - // Delete commitment - delete s_requestCommitments[requestId]; - emit RequestTimedOut(requestId); - } - } - } - - /** - * @dev The allow list is kept on the Oracle contract. This modifier checks if a user is authorized from there. - */ - modifier onlyAuthorizedUsers() { - if (ORACLE_WITH_ALLOWLIST.authorizedReceiverActive() && !ORACLE_WITH_ALLOWLIST.isAuthorizedSender(msg.sender)) { - revert UnauthorizedSender(); - } - _; - } - - modifier onlySubOwner(uint64 subscriptionId) { - address owner = s_subscriptionConfigs[subscriptionId].owner; - if (owner == address(0)) { - revert InvalidSubscription(); - } - if (msg.sender != owner) { - revert MustBeSubOwner(owner); - } - _; - } - - modifier nonReentrant() { - if (s_config.reentrancyLock) { - revert Reentrant(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override onlyOwner returns (bool) { - return true; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsClientInterface.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsClientInterface.sol deleted file mode 100644 index b047a673135..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsClientInterface.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions client interface. - */ -interface FunctionsClientInterface { - /** - * @notice Returns the DON's secp256k1 public key used to encrypt secrets - * @dev All Oracles nodes have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Chainlink Functions response handler called by the designated transmitter node in an OCR round. - * @param requestId The requestId returned by FunctionsClient.sendRequest(). - * @param response Aggregated response from the user code. - * @param err Aggregated error either from the user code or from the execution pipeline. - * Either response or error parameter will be set, but never both. - */ - function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleInterface.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleInterface.sol deleted file mode 100644 index 2076dcc0c37..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleInterface.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import "./FunctionsBillingRegistryInterface.sol"; - -/** - * @title Chainlink Functions oracle interface. - */ -interface FunctionsOracleInterface { - /** - * @notice Gets the stored billing registry address - * @return registryAddress The address of Chainlink Functions billing registry contract - */ - function getRegistry() external view returns (address); - - /** - * @notice Sets the stored billing registry address - * @param registryAddress The new address of Chainlink Functions billing registry contract - */ - function setRegistry(address registryAddress) external; - - /** - * @notice Returns the DON's secp256k1 public key that is used to encrypt secrets - * @dev All nodes on the DON have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey the DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Sets DON's secp256k1 public key used to encrypt secrets - * @dev Used to rotate the key - * @param donPublicKey The new public key - */ - function setDONPublicKey(bytes calldata donPublicKey) external; - - /** - * @notice Sets a per-node secp256k1 public key used to encrypt secrets for that node - * @dev Callable only by contract owner and DON members - * @param node node's address - * @param publicKey node's public key - */ - function setNodePublicKey(address node, bytes calldata publicKey) external; - - /** - * @notice Deletes node's public key - * @dev Callable only by contract owner or the node itself - * @param node node's address - */ - function deleteNodePublicKey(address node) external; - - /** - * @notice Return two arrays of equal size containing DON members' addresses and their corresponding - * public keys (or empty byte arrays if per-node key is not defined) - */ - function getAllNodePublicKeys() external view returns (address[] memory, bytes[] memory); - - /** - * @notice Determine the fee charged by the DON that will be split between signing Node Operators for servicing the request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee( - bytes calldata data, - FunctionsBillingRegistryInterface.RequestBilling calldata billing - ) external view returns (uint96); - - /** - * @notice Estimate the total cost that will be charged to a subscription to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return billedCost Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view returns (uint96); - - /** - * @notice Sends a request (encoded as data) using the provided subscriptionId - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return requestId A unique request identifier (unique per DON) - */ - function sendRequest(uint64 subscriptionId, bytes calldata data, uint32 gasLimit) external returns (bytes32); -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleMigration.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleMigration.sol deleted file mode 100644 index ccc65007842..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleMigration.sol +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracleInterface} from "./FunctionsOracleInterface.sol"; -import {FunctionsBillingRegistryInterface} from "./FunctionsBillingRegistryInterface.sol"; -import {OCR2BaseUpgradeable} from "./OCR2BaseUpgradeable.sol"; -import {AuthorizedOriginReceiverUpgradeable} from "./AuthorizedOriginReceiverUpgradeable.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Oracle contract - * @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsOracleMigration is - Initializable, - FunctionsOracleInterface, - OCR2BaseUpgradeable, - AuthorizedOriginReceiverUpgradeable -{ - event OracleRequest( - bytes32 indexed requestId, - address requestingContract, - address requestInitiator, - uint64 subscriptionId, - address subscriptionOwner, - bytes data - ); - event OracleResponse(bytes32 indexed requestId); - event UserCallbackError(bytes32 indexed requestId, string reason); - event UserCallbackRawError(bytes32 indexed requestId, bytes lowLevelData); - - error EmptyRequestData(); - error InconsistentReportData(); - error EmptyPublicKey(); - error EmptyBillingRegistry(); - error InvalidRequestID(); - error UnauthorizedPublicKeyChange(); - - bytes private s_donPublicKey; - FunctionsBillingRegistryInterface private s_registry; - mapping(address => bytes) private s_nodePublicKeys; - - /** - * @dev Initializes the contract. - */ - function initialize() public initializer { - __OCR2Base_initialize(true); - __AuthorizedOriginReceiver_initialize(true); - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure override returns (string memory) { - return "FunctionsOracle ?.?.?"; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getRegistry() external view override returns (address) { - return address(s_registry); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setRegistry(address registryAddress) external override onlyOwner { - if (registryAddress == address(0)) { - revert EmptyBillingRegistry(); - } - s_registry = FunctionsBillingRegistryInterface(registryAddress); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getDONPublicKey() external view override returns (bytes memory) { - return s_donPublicKey; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { - if (donPublicKey.length == 0) { - revert EmptyPublicKey(); - } - s_donPublicKey = donPublicKey; - } - - /** - * @dev check if node is in current transmitter list - */ - function _isTransmitter(address node) internal view returns (bool) { - address[] memory nodes = this.transmitters(); - for (uint256 i = 0; i < nodes.length; i++) { - if (nodes[i] == node) { - return true; - } - } - return false; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setNodePublicKey(address node, bytes calldata publicKey) external override { - // Owner can set anything. Transmitters can set only their own key. - if (!(msg.sender == owner() || (_isTransmitter(msg.sender) && msg.sender == node))) { - revert UnauthorizedPublicKeyChange(); - } - s_nodePublicKeys[node] = publicKey; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function deleteNodePublicKey(address node) external override { - // Owner can delete anything. Others can delete only their own key. - if (!(msg.sender == owner() || msg.sender == node)) { - revert UnauthorizedPublicKeyChange(); - } - delete s_nodePublicKeys[node]; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getAllNodePublicKeys() external view override returns (address[] memory, bytes[] memory) { - address[] memory nodes = this.transmitters(); - bytes[] memory keys = new bytes[](nodes.length); - for (uint256 i = 0; i < nodes.length; i++) { - keys[i] = s_nodePublicKeys[nodes[i]]; - } - return (nodes, keys); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getRequiredFee( - bytes calldata /* data */, - FunctionsBillingRegistryInterface.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - // NOTE: Optionally, compute additional fee split between nodes of the DON here - // e.g. 0.1 LINK * s_transmitters.length - return 1; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view override registryIsSet returns (uint96) { - FunctionsBillingRegistryInterface.RequestBilling memory billing = FunctionsBillingRegistryInterface.RequestBilling( - subscriptionId, - msg.sender, - gasLimit, - gasPrice - ); - uint96 requiredFee = getRequiredFee(data, billing); - uint96 registryFee = getRequiredFee(data, billing); - return s_registry.estimateCost(gasLimit, gasPrice, requiredFee, registryFee); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function sendRequest( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit - ) external override registryIsSet validateAuthorizedSender returns (bytes32) { - if (data.length == 0) { - revert EmptyRequestData(); - } - bytes32 requestId = s_registry.startBilling( - data, - FunctionsBillingRegistryInterface.RequestBilling(subscriptionId, msg.sender, gasLimit, tx.gasprice) - ); - emit OracleRequest( - requestId, - msg.sender, - tx.origin, - subscriptionId, - s_registry.getSubscriptionOwner(subscriptionId), - data - ); - return requestId; - } - - function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _validateReport( - bytes32 /* configDigest */, - uint40 /* epochAndRound */, - bytes memory /* report */ - ) internal pure override returns (bool) { - // validate within _report to save gas - return true; - } - - function _report( - uint256 initialGas, - address transmitter, - uint8 signerCount, - address[maxNumOracles] memory signers, - bytes calldata report - ) internal override registryIsSet { - bytes32[] memory requestIds; - bytes[] memory results; - bytes[] memory errors; - (requestIds, results, errors) = abi.decode(report, (bytes32[], bytes[], bytes[])); - if (requestIds.length == 0 || requestIds.length != results.length || requestIds.length != errors.length) { - revert ReportInvalid(); - } - - uint256 reportValidationGasShare = (initialGas - gasleft()) / requestIds.length; - - for (uint256 i = 0; i < requestIds.length; i++) { - try - s_registry.fulfillAndBill( - requestIds[i], - results[i], - errors[i], - transmitter, - signers, - signerCount, - reportValidationGasShare, - gasleft() - ) - returns (bool success) { - if (success) { - emit OracleResponse(requestIds[i]); - } else { - emit UserCallbackError(requestIds[i], "error in callback"); - } - } catch (bytes memory reason) { - emit UserCallbackRawError(requestIds[i], reason); - } - } - } - - /** - * @dev Reverts if the the billing registry is not set - */ - modifier registryIsSet() { - if (address(s_registry) == address(0)) { - revert EmptyBillingRegistry(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override returns (bool) { - return msg.sender == owner(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleOriginal.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleOriginal.sol deleted file mode 100644 index 0ff5ad1b6cc..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsOracleOriginal.sol +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {FunctionsOracleInterface} from "./FunctionsOracleInterface.sol"; -import {FunctionsBillingRegistryInterface} from "./FunctionsBillingRegistryInterface.sol"; -import {OCR2BaseUpgradeable} from "./OCR2BaseUpgradeable.sol"; -import {AuthorizedOriginReceiverUpgradeable} from "./AuthorizedOriginReceiverUpgradeable.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @title Functions Oracle contract - * @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - */ -contract FunctionsOracleOriginal is - Initializable, - FunctionsOracleInterface, - OCR2BaseUpgradeable, - AuthorizedOriginReceiverUpgradeable -{ - event OracleRequest( - bytes32 indexed requestId, - address requestingContract, - address requestInitiator, - uint64 subscriptionId, - address subscriptionOwner, - bytes data - ); - event OracleResponse(bytes32 indexed requestId); - event UserCallbackError(bytes32 indexed requestId, string reason); - event UserCallbackRawError(bytes32 indexed requestId, bytes lowLevelData); - - error EmptyRequestData(); - error InconsistentReportData(); - error EmptyPublicKey(); - error EmptyBillingRegistry(); - error InvalidRequestID(); - error UnauthorizedPublicKeyChange(); - - bytes private s_donPublicKey; - FunctionsBillingRegistryInterface private s_registry; - mapping(address => bytes) private s_nodePublicKeys; - - /** - * @dev Initializes the contract. - */ - function initialize() public initializer { - __OCR2Base_initialize(true); - __AuthorizedOriginReceiver_initialize(true); - } - - /** - * @notice The type and version of this contract - * @return Type and version string - */ - function typeAndVersion() external pure override returns (string memory) { - return "FunctionsOracle ?.?.?"; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getRegistry() external view override returns (address) { - return address(s_registry); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setRegistry(address registryAddress) external override onlyOwner { - if (registryAddress == address(0)) { - revert EmptyBillingRegistry(); - } - s_registry = FunctionsBillingRegistryInterface(registryAddress); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getDONPublicKey() external view override returns (bytes memory) { - return s_donPublicKey; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { - if (donPublicKey.length == 0) { - revert EmptyPublicKey(); - } - s_donPublicKey = donPublicKey; - } - - /** - * @dev check if node is in current transmitter list - */ - function _isTransmitter(address node) internal view returns (bool) { - address[] memory nodes = this.transmitters(); - for (uint256 i = 0; i < nodes.length; i++) { - if (nodes[i] == node) { - return true; - } - } - return false; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function setNodePublicKey(address node, bytes calldata publicKey) external override { - // Owner can set anything. Transmitters can set only their own key. - if (!(msg.sender == owner() || (_isTransmitter(msg.sender) && msg.sender == node))) { - revert UnauthorizedPublicKeyChange(); - } - s_nodePublicKeys[node] = publicKey; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function deleteNodePublicKey(address node) external override { - // Owner can delete anything. Others can delete only their own key. - if (!(msg.sender == owner() || msg.sender == node)) { - revert UnauthorizedPublicKeyChange(); - } - delete s_nodePublicKeys[node]; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getAllNodePublicKeys() external view override returns (address[] memory, bytes[] memory) { - address[] memory nodes = this.transmitters(); - bytes[] memory keys = new bytes[](nodes.length); - for (uint256 i = 0; i < nodes.length; i++) { - keys[i] = s_nodePublicKeys[nodes[i]]; - } - return (nodes, keys); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function getRequiredFee( - bytes calldata /* data */, - FunctionsBillingRegistryInterface.RequestBilling memory /* billing */ - ) public pure override returns (uint96) { - // NOTE: Optionally, compute additional fee split between nodes of the DON here - // e.g. 0.1 LINK * s_transmitters.length - return 0; - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view override registryIsSet returns (uint96) { - FunctionsBillingRegistryInterface.RequestBilling memory billing = FunctionsBillingRegistryInterface.RequestBilling( - subscriptionId, - msg.sender, - gasLimit, - gasPrice - ); - uint96 requiredFee = getRequiredFee(data, billing); - uint96 registryFee = getRequiredFee(data, billing); - return s_registry.estimateCost(gasLimit, gasPrice, requiredFee, registryFee); - } - - /** - * @inheritdoc FunctionsOracleInterface - */ - function sendRequest( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit - ) external override registryIsSet validateAuthorizedSender returns (bytes32) { - if (data.length == 0) { - revert EmptyRequestData(); - } - bytes32 requestId = s_registry.startBilling( - data, - FunctionsBillingRegistryInterface.RequestBilling(subscriptionId, msg.sender, gasLimit, tx.gasprice) - ); - emit OracleRequest( - requestId, - msg.sender, - tx.origin, - subscriptionId, - s_registry.getSubscriptionOwner(subscriptionId), - data - ); - return requestId; - } - - function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal override {} - - function _validateReport( - bytes32 /* configDigest */, - uint40 /* epochAndRound */, - bytes memory /* report */ - ) internal pure override returns (bool) { - // validate within _report to save gas - return true; - } - - function _report( - uint256 initialGas, - address transmitter, - uint8 signerCount, - address[maxNumOracles] memory signers, - bytes calldata report - ) internal override registryIsSet { - bytes32[] memory requestIds; - bytes[] memory results; - bytes[] memory errors; - (requestIds, results, errors) = abi.decode(report, (bytes32[], bytes[], bytes[])); - if (requestIds.length == 0 || requestIds.length != results.length || requestIds.length != errors.length) { - revert ReportInvalid(); - } - - uint256 reportValidationGasShare = (initialGas - gasleft()) / requestIds.length; - - for (uint256 i = 0; i < requestIds.length; i++) { - try - s_registry.fulfillAndBill( - requestIds[i], - results[i], - errors[i], - transmitter, - signers, - signerCount, - reportValidationGasShare, - gasleft() - ) - returns (bool success) { - if (success) { - emit OracleResponse(requestIds[i]); - } else { - emit UserCallbackError(requestIds[i], "error in callback"); - } - } catch (bytes memory reason) { - emit UserCallbackRawError(requestIds[i], reason); - } - } - } - - /** - * @dev Reverts if the the billing registry is not set - */ - modifier registryIsSet() { - if (address(s_registry) == address(0)) { - revert EmptyBillingRegistry(); - } - _; - } - - function _canSetAuthorizedSenders() internal view override returns (bool) { - return msg.sender == owner(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2Abstract.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2Abstract.sol deleted file mode 100644 index 02e204585ac..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2Abstract.sol +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {TypeAndVersionInterface} from "../../../../../interfaces/TypeAndVersionInterface.sol"; - -abstract contract OCR2Abstract is TypeAndVersionInterface { - // Maximum number of oracles the offchain reporting protocol is designed for - uint256 internal constant maxNumOracles = 31; - - /** - * @notice triggers a new run of the offchain reporting protocol - * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis - * @param configDigest configDigest of this configuration - * @param configCount ordinal number of this config setting among all config settings over the life of this contract - * @param signers ith element is address ith oracle uses to sign a report - * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method - * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ - event ConfigSet( - uint32 previousConfigBlockNumber, - bytes32 configDigest, - uint64 configCount, - address[] signers, - address[] transmitters, - uint8 f, - bytes onchainConfig, - uint64 offchainConfigVersion, - bytes offchainConfig - ); - - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param signers addresses with which oracles sign the reports - * @param transmitters addresses oracles use to transmit the reports - * @param f number of faulty oracles the system can tolerate - * @param onchainConfig serialized configuration used by the contract (and possibly oracles) - * @param offchainConfigVersion version number for offchainEncoding schema - * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract - */ - function setConfig( - address[] memory signers, - address[] memory transmitters, - uint8 f, - bytes memory onchainConfig, - uint64 offchainConfigVersion, - bytes memory offchainConfig - ) external virtual; - - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData) - */ - function latestConfigDetails() - external - view - virtual - returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); - - function _configDigestFromConfigData( - uint256 chainId, - address contractAddress, - uint64 configCount, - address[] memory signers, - address[] memory transmitters, - uint8 f, - bytes memory onchainConfig, - uint64 offchainConfigVersion, - bytes memory offchainConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - chainId, - contractAddress, - configCount, - signers, - transmitters, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - - /** - * @notice optionally emited to indicate the latest configDigest and epoch for - which a report was successfully transmited. Alternatively, the contract may - use latestConfigDigestAndEpoch with scanLogs set to false. - */ - event Transmitted(bytes32 configDigest, uint32 epoch); - - /** - * @notice optionally returns the latest configDigest and epoch for which a - report was successfully transmitted. Alternatively, the contract may return - scanLogs set to true and use Transmitted events to provide this information - to offchain watchers. - * @return scanLogs indicates whether to rely on the configDigest and epoch - returned or whether to scan logs for the Transmitted event instead. - * @return configDigest - * @return epoch - */ - function latestConfigDigestAndEpoch() - external - view - virtual - returns (bool scanLogs, bytes32 configDigest, uint32 epoch); - - /** - * @notice transmit is called to post a new report to the contract - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ - function transmit( - // NOTE: If these parameters are changed, expectedMsgDataLength and/or - // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly - bytes32[3] calldata reportContext, - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss, - bytes32 rawVs // signatures - ) external virtual; -} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2BaseUpgradeable.sol b/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2BaseUpgradeable.sol deleted file mode 100644 index b768d716583..00000000000 --- a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/OCR2BaseUpgradeable.sol +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {ConfirmedOwnerUpgradeable} from "./ConfirmedOwnerUpgradeable.sol"; -import {OCR2Abstract} from "./OCR2Abstract.sol"; -import {Initializable} from "../../../../../vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol"; - -/** - * @notice Onchain verification of reports from the offchain reporting protocol - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. - * @dev For details on its operation, see the offchain reporting protocol design - * doc, which refers to this contract as simply the "contract". - * @dev This contract is meant to aid rapid development of new applications based on OCR2. - * However, for actual production contracts, it is expected that most of the logic of this contract - * will be folded directly into the application contract. Inheritance prevents us from doing lots - * of juicy storage layout optimizations, leading to a substantial increase in gas cost. - */ -abstract contract OCR2BaseUpgradeable is Initializable, ConfirmedOwnerUpgradeable, OCR2Abstract { - error ReportInvalid(); - - bool internal i_uniqueReports; - - /** - * @dev Initializes the contract. - */ - function __OCR2Base_initialize(bool uniqueReports) internal onlyInitializing { - __ConfirmedOwner_initialize(msg.sender, address(0)); - i_uniqueReports = uniqueReports; - } - - uint256 private constant maxUint32 = (1 << 32) - 1; - - // Storing these fields used on the hot path in a ConfigInfo variable reduces the - // retrieval of all of them to a single SLOAD. If any further fields are - // added, make sure that storage of the struct still takes at most 32 bytes. - struct ConfigInfo { - bytes32 latestConfigDigest; - uint8 f; // TODO: could be optimized by squeezing into one slot - uint8 n; - } - ConfigInfo internal s_configInfo; - - // incremented each time a new config is posted. This count is incorporated - // into the config digest, to prevent replay attacks. - uint32 internal s_configCount; - uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems - // to extract config from logs. - - // Used for s_oracles[a].role, where a is an address, to track the purpose - // of the address, or to indicate that the address is unset. - enum Role { - // No oracle role has been set for address a - Unset, - // Signing address for the s_oracles[a].index'th oracle. I.e., report - // signatures from this oracle should ecrecover back to address a. - Signer, - // Transmission address for the s_oracles[a].index'th oracle. I.e., if a - // report is received by OCR2Aggregator.transmit in which msg.sender is - // a, it is attributed to the s_oracles[a].index'th oracle. - Transmitter - } - - struct Oracle { - uint8 index; // Index of oracle in s_signers/s_transmitters - Role role; // Role of the address which mapped to this struct - } - - mapping(address => Oracle) /* signer OR transmitter address */ internal s_oracles; - - // s_signers contains the signing address of each oracle - address[] internal s_signers; - - // s_transmitters contains the transmission address of each oracle, - // i.e. the address the oracle actually sends transactions to the contract from - address[] internal s_transmitters; - - /* - * Config logic - */ - - // Reverts transaction if config args are invalid - modifier checkConfigValid( - uint256 _numSigners, - uint256 _numTransmitters, - uint256 _f - ) { - require(_numSigners <= maxNumOracles, "too many signers"); - require(_f > 0, "f must be positive"); - require(_numSigners == _numTransmitters, "oracle addresses out of registration"); - require(_numSigners > 3 * _f, "faulty-oracle f too high"); - _; - } - - struct SetConfigArgs { - address[] signers; - address[] transmitters; - uint8 f; - bytes onchainConfig; - uint64 offchainConfigVersion; - bytes offchainConfig; - } - - /// @inheritdoc OCR2Abstract - function latestConfigDigestAndEpoch() - external - view - virtual - override - returns (bool scanLogs, bytes32 configDigest, uint32 epoch) - { - return (true, bytes32(0), uint32(0)); - } - - /** - * @notice sets offchain reporting protocol configuration incl. participating oracles - * @param _signers addresses with which oracles sign the reports - * @param _transmitters addresses oracles use to transmit the reports - * @param _f number of faulty oracles the system can tolerate - * @param _onchainConfig encoded on-chain contract configuration - * @param _offchainConfigVersion version number for offchainEncoding schema - * @param _offchainConfig encoded off-chain oracle configuration - */ - function setConfig( - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _offchainConfigVersion, - bytes memory _offchainConfig - ) external override checkConfigValid(_signers.length, _transmitters.length, _f) onlyOwner { - SetConfigArgs memory args = SetConfigArgs({ - signers: _signers, - transmitters: _transmitters, - f: _f, - onchainConfig: _onchainConfig, - offchainConfigVersion: _offchainConfigVersion, - offchainConfig: _offchainConfig - }); - - _beforeSetConfig(args.f, args.onchainConfig); - - while (s_signers.length != 0) { - // remove any old signer/transmitter addresses - uint256 lastIdx = s_signers.length - 1; - address signer = s_signers[lastIdx]; - address transmitter = s_transmitters[lastIdx]; - delete s_oracles[signer]; - delete s_oracles[transmitter]; - s_signers.pop(); - s_transmitters.pop(); - } - - for (uint256 i = 0; i < args.signers.length; ++i) { - // add new signer/transmitter addresses - require(s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address"); - s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); - require(s_oracles[args.transmitters[i]].role == Role.Unset, "repeated transmitter address"); - s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); - s_signers.push(args.signers[i]); - s_transmitters.push(args.transmitters[i]); - } - s_configInfo.f = args.f; - uint32 previousConfigBlockNumber = s_latestConfigBlockNumber; - s_latestConfigBlockNumber = uint32(block.number); - s_configCount += 1; - { - s_configInfo.latestConfigDigest = configDigestFromConfigData( - block.chainid, - address(this), - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - } - s_configInfo.n = uint8(args.signers.length); - - emit ConfigSet( - previousConfigBlockNumber, - s_configInfo.latestConfigDigest, - s_configCount, - args.signers, - args.transmitters, - args.f, - args.onchainConfig, - args.offchainConfigVersion, - args.offchainConfig - ); - - _afterSetConfig(args.f, args.onchainConfig); - } - - function configDigestFromConfigData( - uint256 _chainId, - address _contractAddress, - uint64 _configCount, - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _encodedConfigVersion, - bytes memory _encodedConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - _chainId, - _contractAddress, - _configCount, - _signers, - _transmitters, - _f, - _onchainConfig, - _encodedConfigVersion, - _encodedConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - - /** - * @notice information about current offchain reporting protocol configuration - * @return configCount ordinal number of current config, out of all configs applied to this contract so far - * @return blockNumber block at which this config was set - * @return configDigest domain-separation tag for current config (see configDigestFromConfigData) - */ - function latestConfigDetails() - external - view - override - returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) - { - return (s_configCount, s_latestConfigBlockNumber, s_configInfo.latestConfigDigest); - } - - /** - * @return list of addresses permitted to transmit reports to this contract - * @dev The list will match the order used to specify the transmitter during setConfig - */ - function transmitters() external view returns (address[] memory) { - return s_transmitters; - } - - function _beforeSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - - function _afterSetConfig(uint8 _f, bytes memory _onchainConfig) internal virtual; - - /** - * @dev hook to allow additional validation of the report by the extending contract - * @param configDigest separation tag for current config (see configDigestFromConfigData) - * @param epochAndRound 27 byte padding, 4-byte epoch and 1-byte round - * @param report serialized report - */ - function _validateReport( - bytes32 configDigest, - uint40 epochAndRound, - bytes memory report - ) internal virtual returns (bool); - - /** - * @dev hook called after the report has been fully validated - * for the extending contract to handle additional logic, such as oracle payment - * @param initialGas the amount of gas before validation - * @param transmitter the address of the account that submitted the report - * @param signers the addresses of all signing accounts - * @param report serialized report - */ - function _report( - uint256 initialGas, - address transmitter, - uint8 signerCount, - address[maxNumOracles] memory signers, - bytes calldata report - ) internal virtual; - - // The constant-length components of the msg.data sent to transmit. - // See the "If we wanted to call sam" example on for example reasoning - // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html - uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT = - 4 + // function selector - 32 * - 3 + // 3 words containing reportContext - 32 + // word containing start location of abiencoded report value - 32 + // word containing location start of abiencoded rs value - 32 + // word containing start location of abiencoded ss value - 32 + // rawVs value - 32 + // word containing length of report - 32 + // word containing length rs - 32 + // word containing length of ss - 0; // placeholder - - function requireExpectedMsgDataLength( - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss - ) private pure { - // calldata will never be big enough to make this overflow - uint256 expected = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) + - report.length + // one byte pure entry in _report - rs.length * - 32 + // 32 bytes per entry in _rs - ss.length * - 32 + // 32 bytes per entry in _ss - 0; // placeholder - require(msg.data.length == expected, "calldata length mismatch"); - } - - /** - * @notice transmit is called to post a new report to the contract - * @param report serialized report, which the signatures are signing. - * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries - * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries - * @param rawVs ith element is the the V component of the ith signature - */ - function transmit( - // NOTE: If these parameters are changed, expectedMsgDataLength and/or - // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly - bytes32[3] calldata reportContext, - bytes calldata report, - bytes32[] calldata rs, - bytes32[] calldata ss, - bytes32 rawVs // signatures - ) external override { - uint256 initialGas = gasleft(); // This line must come first - - { - // reportContext consists of: - // reportContext[0]: ConfigDigest - // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round - // reportContext[2]: ExtraHash - bytes32 configDigest = reportContext[0]; - uint32 epochAndRound = uint32(uint256(reportContext[1])); - - if (!_validateReport(configDigest, epochAndRound, report)) { - revert ReportInvalid(); - } - - emit Transmitted(configDigest, uint32(epochAndRound >> 8)); - - ConfigInfo memory configInfo = s_configInfo; - require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); - - requireExpectedMsgDataLength(report, rs, ss); - - uint256 expectedNumSignatures; - if (i_uniqueReports) { - expectedNumSignatures = (configInfo.n + configInfo.f) / 2 + 1; - } else { - expectedNumSignatures = configInfo.f + 1; - } - - require(rs.length == expectedNumSignatures, "wrong number of signatures"); - require(rs.length == ss.length, "signatures out of registration"); - - Oracle memory transmitter = s_oracles[msg.sender]; - require( // Check that sender is authorized to report - transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index], - "unauthorized transmitter" - ); - } - - address[maxNumOracles] memory signed; - uint8 signerCount = 0; - - { - // Verify signatures attached to report - bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext)); - - Oracle memory o; - for (uint256 i = 0; i < rs.length; ++i) { - address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); - o = s_oracles[signer]; - require(o.role == Role.Signer, "address not authorized to sign"); - require(signed[o.index] == address(0), "non-unique signature"); - signed[o.index] = signer; - signerCount += 1; - } - } - - _report(initialGas, msg.sender, signerCount, signed, report); - } -} diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsClient.t.sol b/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsClient.t.sol deleted file mode 100644 index b2740b7e297..00000000000 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsClient.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -/// @notice #constructor -contract FunctionsClient_Constructor { - -} - -/// @notice #_sendRequest -contract FunctionsClient__SendRequest { - -} - -/// @notice #fulfillRequest -contract FunctionsClient_FulfillRequest { - -} - -/// @notice #handleOracleFulfillment -contract FunctionsClient_HandleOracleFulfillment { - -} diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRequest.t.sol b/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRequest.t.sol deleted file mode 100644 index a274bbe8cfc..00000000000 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRequest.t.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -/// @notice #REQUEST_DATA_VERSION -contract FunctionsRequest_REQUEST_DATA_VERSION { - -} - -/// @notice #DEFAULT_BUFFER_SIZE -contract FunctionsRequest_DEFAULT_BUFFER_SIZE { - -} - -/// @notice #encodeCBOR -contract FunctionsRequest_EncodeCBOR { - -} - -/// @notice #initializeRequest -contract FunctionsRequest_InitializeRequest { - -} - -/// @notice #initializeRequestForInlineJavaScript -contract FunctionsRequest_InitializeRequestForInlineJavaScript { - -} - -/// @notice #addSecretsReference -contract FunctionsRequest_AddSecretsReference { - -} - -/// @notice #addDONHostedSecrets -contract FunctionsRequest_AddDONHostedSecrets { - -} - -/// @notice #setArgs -contract FunctionsRequest_SetArgs { - -} - -/// @notice #setBytesArgs -contract FunctionsRequest_SetBytesArgs { - -} diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/OCR2.t.sol b/contracts/src/v0.8/functions/tests/v1_0_0/OCR2.t.sol deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/BaseTest.t.sol b/contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol similarity index 100% rename from contracts/src/v0.8/functions/tests/v1_0_0/BaseTest.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/BaseTest.t.sol diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol similarity index 60% rename from contracts/src/v0.8/functions/tests/v1_0_0/FunctionsCoordinator.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol index 088de631d06..14188fdc04a 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsCoordinator.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol @@ -1,89 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {FunctionsCoordinator} from "../../dev/v1_0_0/FunctionsCoordinator.sol"; -import {FunctionsBilling} from "../../dev/v1_0_0/FunctionsBilling.sol"; -import {FunctionsRequest} from "../../dev/v1_0_0/libraries/FunctionsRequest.sol"; +import {FunctionsCoordinator} from "../../dev/v1_X/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; -import {FunctionsSubscriptionSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; - -// ================================================================ -// | Functions Coordinator | -// ================================================================ - -/// @notice #constructor -contract FunctionsCoordinator_Constructor { - -} - -/// @notice #getThresholdPublicKey -contract FunctionsCoordinator_GetThresholdPublicKey { - -} - -/// @notice #setThresholdPublicKey -contract FunctionsCoordinator_SetThresholdPublicKey { - -} - -/// @notice #getDONPublicKey -contract FunctionsCoordinator_GetDONPublicKey { - -} - -/// @notice #setDONPublicKey -contract FunctionsCoordinator__SetDONPublicKey { - -} - -/// @notice #_isTransmitter -contract FunctionsCoordinator_IsTransmitter { - -} - -/// @notice #setNodePublicKey -contract FunctionsCoordinator_SetNodePublicKey { - -} - -/// @notice #deleteNodePublicKey -contract FunctionsCoordinator_DeleteNodePublicKey { - -} - -/// @notice #getAllNodePublicKeys -contract FunctionsCoordinator_GetAllNodePublicKeys { - -} - -/// @notice #startRequest -contract FunctionsCoordinator_StartRequest { - -} - -/// @notice #_beforeSetConfig -contract FunctionsCoordinator__BeforeSetConfig { - -} - -/// @notice #_getTransmitters -contract FunctionsCoordinator__GetTransmitters { - -} - -/// @notice #_report -contract FunctionsCoordinator__Report { - -} - -/// @notice #_onlyOwner -contract FunctionsCoordinator__OnlyOwner { - -} - -// ================================================================ -// | Functions Billing | -// ================================================================ +import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; /// @notice #constructor contract FunctionsBilling_Constructor { @@ -91,8 +13,22 @@ contract FunctionsBilling_Constructor { } /// @notice #getConfig -contract FunctionsBilling_GetConfig { +contract FunctionsBilling_GetConfig is FunctionsRouterSetup { + function test_GetConfig_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + assertEq(config.feedStalenessSeconds, getCoordinatorConfig().feedStalenessSeconds); + assertEq(config.gasOverheadBeforeCallback, getCoordinatorConfig().gasOverheadBeforeCallback); + assertEq(config.gasOverheadAfterCallback, getCoordinatorConfig().gasOverheadAfterCallback); + assertEq(config.requestTimeoutSeconds, getCoordinatorConfig().requestTimeoutSeconds); + assertEq(config.donFee, getCoordinatorConfig().donFee); + assertEq(config.maxSupportedRequestDataVersion, getCoordinatorConfig().maxSupportedRequestDataVersion); + assertEq(config.fulfillmentGasPriceOverEstimationBP, getCoordinatorConfig().fulfillmentGasPriceOverEstimationBP); + assertEq(config.fallbackNativePerUnitLink, getCoordinatorConfig().fallbackNativePerUnitLink); + } } /// @notice #updateConfig @@ -117,7 +53,7 @@ contract FunctionsBilling_GetWeiPerUnitLink { /// @notice #_getJuelsPerGas contract FunctionsBilling__GetJuelsPerGas { - + // TODO: make contract internal function helper } /// @notice #estimateCost @@ -136,13 +72,13 @@ contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5_500; uint256 gasPriceWei = REASONABLE_GAS_PRICE_CEILING + 1; @@ -152,17 +88,17 @@ contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { s_functionsCoordinator.estimateCost(s_subscriptionId, requestData, callbackGasLimit, gasPriceWei); } - function test_EstimateCost_Success() public { + function test_EstimateCost_SuccessLowGasPrice() public { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5_500; uint256 gasPriceWei = 1; @@ -173,29 +109,54 @@ contract FunctionsBilling_EstimateCost is FunctionsSubscriptionSetup { callbackGasLimit, gasPriceWei ); - uint96 expectedCostEstimate = 10873200; + uint96 expectedCostEstimate = 16375000000000200; + assertEq(costEstimate, expectedCostEstimate); + } + + function test_EstimateCost_Success() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest._initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); + + uint32 callbackGasLimit = 5_500; + uint256 gasPriceWei = 5000000000; // 5 gwei + + uint96 costEstimate = s_functionsCoordinator.estimateCost( + s_subscriptionId, + requestData, + callbackGasLimit, + gasPriceWei + ); + uint96 expectedCostEstimate = 81875000000000200; assertEq(costEstimate, expectedCostEstimate); } } /// @notice #_calculateCostEstimate contract FunctionsBilling__CalculateCostEstimate { - + // TODO: make contract internal function helper } /// @notice #_startBilling contract FunctionsBilling__StartBilling { - + // TODO: make contract internal function helper } /// @notice #_computeRequestId contract FunctionsBilling__ComputeRequestId { - + // TODO: make contract internal function helper } /// @notice #_fulfillAndBill contract FunctionsBilling__FulfillAndBill { - + // TODO: make contract internal function helper } /// @notice #deleteCommitment @@ -254,64 +215,10 @@ contract FunctionsBilling_OracleWithdrawAll is FunctionsMultipleFulfillmentsSetu /// @notice #_getTransmitters contract FunctionsBilling__GetTransmitters { - + // TODO: make contract internal function helper } /// @notice #_disperseFeePool contract FunctionsBilling__DisperseFeePool { - -} - -// ================================================================ -// | OCR2Base | -// ================================================================ - -/// @notice #constructor -contract OCR2Base_Constructor { - -} - -/// @notice #checkConfigValid -contract OCR2Base_CheckConfigValid { - -} - -/// @notice #latestConfigDigestAndEpoch -contract OCR2Base_LatestConfigDigestAndEpoch { - -} - -/// @notice #setConfig -contract OCR2Base_SetConfig { - -} - -/// @notice #configDigestFromConfigData -contract OCR2Base_ConfigDigestFromConfigData { - -} - -/// @notice #latestConfigDetails -contract OCR2Base_LatestConfigDetails { - -} - -/// @notice #transmitters -contract OCR2Base_Transmitters { - -} - -/// @notice #_report -contract OCR2Base__Report { - -} - -/// @notice #requireExpectedMsgDataLength -contract OCR2Base_RequireExpectedMsgDataLength { - -} - -/// @notice #transmit -contract OCR2Base_Transmit { - + // TODO: make contract internal function helper } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol new file mode 100644 index 00000000000..d6a3be16847 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsClient.t.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; + +import {FunctionsSubscriptionSetup} from "./Setup.t.sol"; + +/// @notice #constructor +contract FunctionsClient_Constructor { + +} + +/// @notice #_sendRequest +contract FunctionsClient__SendRequest is FunctionsSubscriptionSetup { + // TODO: make contract internal function helper + + function test__SendRequest_RevertIfInvalidCallbackGasLimit() public { + // Build minimal valid request data + string memory sourceCode = "return 'hello world';"; + FunctionsRequest.Request memory request; + FunctionsRequest._initializeRequest( + request, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + sourceCode + ); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); + + uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); + uint8 callbackGasLimitsIndexSelector = uint8(subscriptionFlags[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + + FunctionsRouter.Config memory config = s_functionsRouter.getConfig(); + uint32[] memory _maxCallbackGasLimits = config.maxCallbackGasLimits; + uint32 maxCallbackGasLimit = _maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + + vm.expectRevert(abi.encodeWithSelector(FunctionsRouter.GasLimitTooBig.selector, maxCallbackGasLimit)); + s_functionsClient.sendRequestBytes(requestData, s_subscriptionId, 500_000, s_donId); + } +} + +/// @notice #fulfillRequest +contract FunctionsClient_FulfillRequest { + +} + +/// @notice #handleOracleFulfillment +contract FunctionsClient_HandleOracleFulfillment { + +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol new file mode 100644 index 00000000000..893aa6408b6 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsCoordinator} from "../../dev/v1_X/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; + +import {FunctionsRouterSetup} from "./Setup.t.sol"; + +/// @notice #constructor +contract FunctionsCoordinator_Constructor is FunctionsRouterSetup { + function test_Constructor_Success() public { + assertEq(s_functionsCoordinator.typeAndVersion(), "Functions Coordinator v1.1.0"); + assertEq(s_functionsCoordinator.owner(), OWNER_ADDRESS); + } +} + +/// @notice #getThresholdPublicKey +contract FunctionsCoordinator_GetThresholdPublicKey { + +} + +/// @notice #setThresholdPublicKey +contract FunctionsCoordinator_SetThresholdPublicKey { + +} + +/// @notice #getDONPublicKey +contract FunctionsCoordinator_GetDONPublicKey { + +} + +/// @notice #setDONPublicKey +contract FunctionsCoordinator__SetDONPublicKey { + +} + +/// @notice #_isTransmitter +contract FunctionsCoordinator_IsTransmitter { + // TODO: make contract internal function helper +} + +/// @notice #setNodePublicKey +contract FunctionsCoordinator_SetNodePublicKey { + +} + +/// @notice #deleteNodePublicKey +contract FunctionsCoordinator_DeleteNodePublicKey { + +} + +/// @notice #getAllNodePublicKeys +contract FunctionsCoordinator_GetAllNodePublicKeys { + +} + +/// @notice #startRequest +contract FunctionsCoordinator_StartRequest { + +} + +/// @notice #_beforeSetConfig +contract FunctionsCoordinator__BeforeSetConfig { + // TODO: make contract internal function helper +} + +/// @notice #_getTransmitters +contract FunctionsCoordinator__GetTransmitters { + // TODO: make contract internal function helper +} + +/// @notice #_report +contract FunctionsCoordinator__Report { + +} + +/// @notice #_onlyOwner +contract FunctionsCoordinator__OnlyOwner { + +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol new file mode 100644 index 00000000000..5457a221b61 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRequest.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; + +import {Test} from "forge-std/Test.sol"; + +/// @notice #REQUEST_DATA_VERSION +contract FunctionsRequest_REQUEST_DATA_VERSION is Test { + function test_REQUEST_DATA_VERSION() public { + // Exposes REQUEST_DATA_VERSION + assertEq(FunctionsRequest.REQUEST_DATA_VERSION, 1); + } +} + +/// @notice #DEFAULT_BUFFER_SIZE +contract FunctionsRequest_DEFAULT_BUFFER_SIZE is Test { + function test_DEFAULT_BUFFER_SIZE() public { + // Exposes DEFAULT_BUFFER_SIZE + assertEq(FunctionsRequest.DEFAULT_BUFFER_SIZE, 256); + } +} + +/// @notice #encodeCBOR +contract FunctionsRequest_EncodeCBOR is Test { + function test_EncodeCBOR_Success() public { + // Exposes DEFAULT_BUFFER_SIZE + assertEq(FunctionsRequest.DEFAULT_BUFFER_SIZE, 256); + } +} + +/// @notice #initializeRequest +contract FunctionsRequest_InitializeRequest is Test { + +} + +/// @notice #initializeRequestForInlineJavaScript +contract FunctionsRequest_InitializeRequestForInlineJavaScript is Test { + +} + +/// @notice #addSecretsReference +contract FunctionsRequest_AddSecretsReference is Test { + +} + +/// @notice #addDONHostedSecrets +contract FunctionsRequest_AddDONHostedSecrets is Test { + +} + +/// @notice #setArgs +contract FunctionsRequest_SetArgs is Test { + +} + +/// @notice #setBytesArgs +contract FunctionsRequest_SetBytesArgs is Test { + +} diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol similarity index 92% rename from contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRouter.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol index 1a858c28df6..b9b6e1d5746 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {FunctionsRouter} from "../../dev/v1_0_0/FunctionsRouter.sol"; -import {FunctionsSubscriptions} from "../../dev/v1_0_0/FunctionsSubscriptions.sol"; -import {FunctionsCoordinator} from "../../dev/v1_0_0/FunctionsCoordinator.sol"; -import {FunctionsBilling} from "../../dev/v1_0_0/FunctionsBilling.sol"; -import {FunctionsRequest} from "../../dev/v1_0_0/libraries/FunctionsRequest.sol"; -import {FunctionsResponse} from "../../dev/v1_0_0/libraries/FunctionsResponse.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {FunctionsCoordinator} from "../../dev/v1_X/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {FunctionsCoordinatorTestHelper} from "./testhelpers/FunctionsCoordinatorTestHelper.sol"; import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; @@ -206,13 +206,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); bytes32 invalidDonId = bytes32("this does not exist"); @@ -230,13 +230,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); bytes32 incorrectDonId = s_functionsRouter.getAllowListId(); @@ -257,13 +257,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); vm.expectRevert("Pausable: paused"); s_functionsRouter.sendRequest(s_subscriptionId, requestData, FunctionsRequest.REQUEST_DATA_VERSION, 5000, s_donId); @@ -273,13 +273,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint64 invalidSubscriptionId = 123456789; @@ -300,13 +300,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); vm.expectRevert(FunctionsSubscriptions.InvalidConsumer.selector); s_functionsRouter.sendRequest(s_subscriptionId, requestData, FunctionsRequest.REQUEST_DATA_VERSION, 5000, s_donId); @@ -316,13 +316,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); @@ -364,13 +364,13 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5000; vm.expectRevert(FunctionsBilling.InsufficientBalance.selector); @@ -388,14 +388,14 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); uint32 callbackGasLimit = 5_000; - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); // Send a first request that will remain pending bytes32 requestId = s_functionsRouter.sendRequest( @@ -454,20 +454,16 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5000; - bytes32 expectedRequestId = keccak256( - abi.encode(address(s_functionsCoordinator), OWNER_ADDRESS, s_subscriptionId, 1) - ); - uint96 costEstimate = s_functionsCoordinator.estimateCost( s_subscriptionId, requestData, @@ -477,25 +473,6 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { vm.recordLogs(); - // topic0 (function signature, always checked), topic1 (true), topic2 (true), topic3 (true), and data (true). - bool checkTopic1 = true; - bool checkTopic2 = true; - bool checkTopic3 = true; - bool checkData = true; - vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit RequestStart({ - requestId: expectedRequestId, - donId: s_donId, - subscriptionId: s_subscriptionId, - subscriptionOwner: OWNER_ADDRESS, - requestingContract: OWNER_ADDRESS, - requestInitiator: OWNER_ADDRESS, - data: requestData, - dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, - callbackGasLimit: callbackGasLimit, - estimatedTotalCostJuels: costEstimate - }); - bytes32 requestIdFromReturn = s_functionsRouter.sendRequest( s_subscriptionId, requestData, @@ -506,9 +483,24 @@ contract FunctionsRouter_SendRequest is FunctionsSubscriptionSetup { // Get requestId from RequestStart event log topic 1 Vm.Log[] memory entries = vm.getRecordedLogs(); - bytes32 requestIdFromEvent = entries[2].topics[1]; + bytes32 requestIdFromEvent = entries[1].topics[1]; + bytes32 donIdFromEvent = entries[1].topics[2]; + bytes32 subscriptionIdFromEvent = entries[1].topics[3]; + + bytes memory expectedRequestData = abi.encode( + OWNER_ADDRESS, + OWNER_ADDRESS, + OWNER_ADDRESS, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + costEstimate + ); assertEq(requestIdFromReturn, requestIdFromEvent); + assertEq(donIdFromEvent, s_donId); + assertEq(subscriptionIdFromEvent, bytes32(uint256(s_subscriptionId))); + assertEq(expectedRequestData, entries[1].data); } } @@ -542,13 +534,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); bytes32 invalidDonId = bytes32("this does not exist"); @@ -566,13 +558,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); bytes32 incorrectDonId = s_functionsRouter.getAllowListId(); @@ -593,13 +585,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); vm.expectRevert("Pausable: paused"); s_functionsRouter.sendRequestToProposed( @@ -615,13 +607,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint64 invalidSubscriptionId = 123456789; @@ -642,13 +634,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); vm.expectRevert(FunctionsSubscriptions.InvalidConsumer.selector); s_functionsRouter.sendRequestToProposed( @@ -664,13 +656,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint8 MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; bytes32 subscriptionFlags = s_functionsRouter.getFlags(s_subscriptionId); @@ -712,13 +704,13 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5000; vm.expectRevert(FunctionsBilling.InsufficientBalance.selector); @@ -749,20 +741,16 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Build minimal valid request data string memory sourceCode = "return 'hello world';"; FunctionsRequest.Request memory request; - FunctionsRequest.initializeRequest( + FunctionsRequest._initializeRequest( request, FunctionsRequest.Location.Inline, FunctionsRequest.CodeLanguage.JavaScript, sourceCode ); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); uint32 callbackGasLimit = 5000; - bytes32 expectedRequestId = keccak256( - abi.encode(address(s_functionsCoordinator2), OWNER_ADDRESS, s_subscriptionId, 1) - ); - uint96 costEstimate = s_functionsCoordinator2.estimateCost( s_subscriptionId, requestData, @@ -772,25 +760,6 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { vm.recordLogs(); - // topic0 (function signature, always checked), topic1 (true), topic2 (true), topic3 (true), and data (true). - bool checkTopic1 = true; - bool checkTopic2 = true; - bool checkTopic3 = true; - bool checkData = true; - vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit RequestStart({ - requestId: expectedRequestId, - donId: s_donId, - subscriptionId: s_subscriptionId, - subscriptionOwner: OWNER_ADDRESS, - requestingContract: OWNER_ADDRESS, - requestInitiator: OWNER_ADDRESS, - data: requestData, - dataVersion: FunctionsRequest.REQUEST_DATA_VERSION, - callbackGasLimit: callbackGasLimit, - estimatedTotalCostJuels: costEstimate - }); - bytes32 requestIdFromReturn = s_functionsRouter.sendRequestToProposed( s_subscriptionId, requestData, @@ -801,9 +770,24 @@ contract FunctionsRouter_SendRequestToProposed is FunctionsSubscriptionSetup { // Get requestId from RequestStart event log topic 1 Vm.Log[] memory entries = vm.getRecordedLogs(); - bytes32 requestIdFromEvent = entries[2].topics[1]; + bytes32 requestIdFromEvent = entries[1].topics[1]; + bytes32 donIdFromEvent = entries[1].topics[2]; + bytes32 subscriptionIdFromEvent = entries[1].topics[3]; + + bytes memory expectedRequestData = abi.encode( + OWNER_ADDRESS, + OWNER_ADDRESS, + OWNER_ADDRESS, + requestData, + FunctionsRequest.REQUEST_DATA_VERSION, + callbackGasLimit, + costEstimate + ); assertEq(requestIdFromReturn, requestIdFromEvent); + assertEq(donIdFromEvent, s_donId); + assertEq(subscriptionIdFromEvent, bytes32(uint256(s_subscriptionId))); + assertEq(expectedRequestData, entries[1].data); } } @@ -1127,7 +1111,7 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { emit RequestProcessed({ requestId: requestId, subscriptionId: s_subscriptionId, - totalCostJuels: _getExpectedCost(1379), // gasUsed is manually taken + totalCostJuels: _getExpectedCost(1822), // gasUsed is manually taken transmitter: NOP_TRANSMITTER_ADDRESS_1, resultCode: FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR, response: bytes(response), @@ -1237,7 +1221,7 @@ contract FunctionsRouter_Fulfill is FunctionsClientRequestSetup { emit RequestProcessed({ requestId: s_requests[requestToFulfill].requestId, subscriptionId: s_subscriptionId, - totalCostJuels: _getExpectedCost(5371), // gasUsed is manually taken + totalCostJuels: _getExpectedCost(5393), // gasUsed is manually taken transmitter: NOP_TRANSMITTER_ADDRESS_1, resultCode: FunctionsResponse.FulfillResult.FULFILLED, response: bytes(response), diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol similarity index 91% rename from contracts/src/v0.8/functions/tests/v1_0_0/FunctionsSubscriptions.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index ea5ec0dd683..8046bf7d939 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.19; import {BaseTest} from "./BaseTest.t.sol"; -import {FunctionsRouter} from "../../dev/v1_0_0/FunctionsRouter.sol"; -import {FunctionsSubscriptions} from "../../dev/v1_0_0/FunctionsSubscriptions.sol"; -import {FunctionsResponse} from "../../dev/v1_0_0/libraries/FunctionsResponse.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; @@ -95,7 +95,7 @@ contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscription string[] memory args = new string[](0); bytes[] memory bytesArgs = new bytes[](0); - s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5000); + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5500); s_functionsRouter.ownerCancelSubscription(s_subscriptionId); } @@ -130,8 +130,12 @@ contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscription contract FunctionsSubscriptions_RecoverFunds is FunctionsRouterSetup { event FundsRecovered(address to, uint256 amount); - function test_RecoverFunds_Success() public { - uint256 fundsTransferred = 1 * 1e18; // 1 LINK + function test_RecoverFunds_Success(uint64 fundsTransferred) public { + //amount must be less than LINK total supply + vm.assume(fundsTransferred < 1_000_000_000 * 1e18); + vm.assume(fundsTransferred > 0); + + // uint256 fundsTransferred = 1 * 1e18; // 1 LINK s_linkToken.transfer(address(s_functionsRouter), fundsTransferred); // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). @@ -268,6 +272,14 @@ contract FunctionsSubscriptions_OwnerWithdraw is FunctionsFulfillmentSetup { // s_functionsRouter.ownerWithdraw(OWNER_ADDRESS, amountToWithdraw); } + function test_OwnerWithdraw_SuccessIfRecipientAddressZero() public { + uint256 balanceBefore = s_linkToken.balanceOf(address(0)); + uint96 amountToWithdraw = s_fulfillmentRouterOwnerBalance; + s_functionsRouter.ownerWithdraw(address(0), amountToWithdraw); + uint256 balanceAfter = s_linkToken.balanceOf(address(0)); + assertEq(balanceBefore + s_fulfillmentRouterOwnerBalance, balanceAfter); + } + function test_OwnerWithdraw_SuccessIfNoAmount() public { uint256 balanceBefore = s_linkToken.balanceOf(OWNER_ADDRESS); uint96 amountToWithdraw = 0; @@ -298,35 +310,53 @@ contract FunctionsSubscriptions_OwnerWithdraw is FunctionsFulfillmentSetup { /// @notice #onTokenTransfer contract FunctionsSubscriptions_OnTokenTransfer is FunctionsSubscriptionSetup { - function test_OnTokenTransfer_RevertIfPaused() public { + function test_OnTokenTransfer_RevertIfPaused(uint96 fundingAmount) public { + // Funding amount must be less than LINK total supply + vm.assume(fundingAmount < 1_000_000_000 * 1e18); + vm.assume(fundingAmount > 0); + s_functionsRouter.pause(); vm.expectRevert("Pausable: paused"); - uint96 fundingAmount = 100; s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNotLink() public { + function test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96 fundingAmount) public { + // Funding amount must be less than LINK total supply + vm.assume(fundingAmount < 1_000_000_000 * 1e18); + vm.assume(fundingAmount > 0); + vm.expectRevert(FunctionsSubscriptions.OnlyCallableFromLink.selector); - uint96 fundingAmount = 100; s_functionsRouter.onTokenTransfer(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNoCalldata() public { + function test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96 fundingAmount) public { + // Funding amount must be less than LINK total supply + vm.assume(fundingAmount < 1_000_000_000 * 1e18); + vm.assume(fundingAmount > 0); + vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); - uint96 fundingAmount = 100; s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, new bytes(0)); } - function test_OnTokenTransfer_RevertIfCallerIsNoSubscription() public { + function test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96 fundingAmount) public { + // Funding amount must be less than LINK total supply + vm.assume(fundingAmount < 1_000_000_000 * 1e18); + vm.assume(fundingAmount > 0); + vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); - uint96 fundingAmount = 100; uint64 invalidSubscriptionId = 123456789; s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(invalidSubscriptionId)); } - function test_OnTokenTransfer_Success() public { - uint96 fundingAmount = 100; + function test_OnTokenTransfer_Success(uint96 fundingAmount) public { uint96 subscriptionBalanceBefore = s_functionsRouter.getSubscription(s_subscriptionId).balance; + + // Funding amount must be less than LINK total supply + uint96 TOTAL_LINK = 1_000_000_000 * 1e18; + // Some of the total supply is already in the subscription account + vm.assume(fundingAmount < TOTAL_LINK - subscriptionBalanceBefore); + vm.assume(fundingAmount > 0); + s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); uint96 subscriptionBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).balance; assertEq(subscriptionBalanceBefore + fundingAmount, subscriptionBalanceAfter); @@ -541,13 +571,14 @@ contract FunctionsSubscriptions_CreateSubscriptionWithConsumer is FunctionsClien assertEq(firstCallSubscriptionId, 1); assertEq(s_functionsRouter.getSubscription(firstCallSubscriptionId).consumers[0], address(s_functionsClient)); + // Consumer can be address(0) vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); emit SubscriptionCreated(2, OWNER_ADDRESS); vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit SubscriptionConsumerAdded(2, address(s_functionsClient)); - uint64 secondCallSubscriptionId = s_functionsRouter.createSubscriptionWithConsumer(address(s_functionsClient)); + emit SubscriptionConsumerAdded(2, address(0)); + uint64 secondCallSubscriptionId = s_functionsRouter.createSubscriptionWithConsumer(address(0)); assertEq(secondCallSubscriptionId, 2); - assertEq(s_functionsRouter.getSubscription(secondCallSubscriptionId).consumers[0], address(s_functionsClient)); + assertEq(s_functionsRouter.getSubscription(secondCallSubscriptionId).consumers[0], address(0)); vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); emit SubscriptionCreated(3, OWNER_ADDRESS); @@ -579,13 +610,15 @@ contract FunctionsSubscriptions_CreateSubscriptionWithConsumer is FunctionsClien contract FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer is FunctionsSubscriptionSetup { uint256 internal NEW_OWNER_PRIVATE_KEY_WITH_TOS = 0x3; address internal NEW_OWNER_ADDRESS_WITH_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITH_TOS); - uint256 internal NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS = 0x4; + uint256 internal NEW_OWNER_PRIVATE_KEY_WITH_TOS2 = 0x4; + address internal NEW_OWNER_ADDRESS_WITH_TOS2 = vm.addr(NEW_OWNER_PRIVATE_KEY_WITH_TOS2); + uint256 internal NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS = 0x5; address internal NEW_OWNER_ADDRESS_WITHOUT_TOS = vm.addr(NEW_OWNER_PRIVATE_KEY_WITHOUT_TOS); function setUp() public virtual override { FunctionsSubscriptionSetup.setUp(); - // Accept ToS as new owner + // Accept ToS as new owner #1 vm.stopPrank(); vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS); bytes32 message = s_termsOfServiceAllowList.getMessage(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS); @@ -593,6 +626,20 @@ contract FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer is FunctionsSub (uint8 v, bytes32 r, bytes32 s) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); s_termsOfServiceAllowList.acceptTermsOfService(NEW_OWNER_ADDRESS_WITH_TOS, NEW_OWNER_ADDRESS_WITH_TOS, r, s, v); + // Accept ToS as new owner #2 + vm.stopPrank(); + vm.startPrank(NEW_OWNER_ADDRESS_WITH_TOS2); + bytes32 message2 = s_termsOfServiceAllowList.getMessage(NEW_OWNER_ADDRESS_WITH_TOS2, NEW_OWNER_ADDRESS_WITH_TOS2); + bytes32 prefixedMessage2 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message2)); + (uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage2); + s_termsOfServiceAllowList.acceptTermsOfService( + NEW_OWNER_ADDRESS_WITH_TOS2, + NEW_OWNER_ADDRESS_WITH_TOS2, + r2, + s2, + v2 + ); + vm.stopPrank(); vm.startPrank(OWNER_ADDRESS); } @@ -653,6 +700,24 @@ contract FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer is FunctionsSub s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); assertEq(s_functionsRouter.getSubscription(s_subscriptionId).proposedOwner, NEW_OWNER_ADDRESS_WITH_TOS); } + + function test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() public { + // topic0 (function signature, always checked), topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionOwnerTransferRequested(s_subscriptionId, OWNER_ADDRESS, NEW_OWNER_ADDRESS_WITH_TOS); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); + assertEq(s_functionsRouter.getSubscription(s_subscriptionId).proposedOwner, NEW_OWNER_ADDRESS_WITH_TOS); + + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit SubscriptionOwnerTransferRequested(s_subscriptionId, OWNER_ADDRESS, NEW_OWNER_ADDRESS_WITH_TOS2); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS2); + assertEq(s_functionsRouter.getSubscription(s_subscriptionId).proposedOwner, NEW_OWNER_ADDRESS_WITH_TOS2); + } } /// @notice #acceptSubscriptionOwnerTransfer @@ -735,6 +800,13 @@ contract FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer is FunctionsSubs event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); function test_AcceptSubscriptionOwnerTransfer_Success() public { + // Can transfer ownership with a pending request + string memory sourceCode = "return 'hello world';"; + bytes memory secrets; + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + s_functionsClient.sendRequest(s_donId, sourceCode, secrets, args, bytesArgs, s_subscriptionId, 5500); + s_functionsRouter.proposeSubscriptionOwnerTransfer(s_subscriptionId, NEW_OWNER_ADDRESS_WITH_TOS); // Send as new owner, who has accepted Terms of Service @@ -1184,7 +1256,18 @@ contract FunctionsSubscriptions_SetFlags is FunctionsSubscriptionSetup { /// @notice #getFlags contract FunctionsSubscriptions_GetFlags is FunctionsSubscriptionSetup { - function test_GetFlags_Success() public { + function test_GetFlags_SuccessInvalidSubscription() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 invalidSubscriptionId = 999999; + + bytes32 flags = s_functionsRouter.getFlags(invalidSubscriptionId); + assertEq(flags, bytes32(0)); + } + + function test_GetFlags_SuccessValidSubscription() public { // Set flags bytes32 flagsToSet = bytes32("1"); s_functionsRouter.setFlags(s_subscriptionId, flagsToSet); diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsTermsOfServiceAllowList.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol similarity index 88% rename from contracts/src/v0.8/functions/tests/v1_0_0/FunctionsTermsOfServiceAllowList.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol index d8f03ba3ebf..450ec48d504 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/FunctionsTermsOfServiceAllowList.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {TermsOfServiceAllowList} from "../../dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup} from "./Setup.t.sol"; @@ -154,6 +154,26 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, address(s_functionsClientHelper), r, s, v); } + function testAcceptTermsOfService_InvalidSigner_vuln() public { + // Set the signer as the zero address + TermsOfServiceAllowList.Config memory allowListConfig; + allowListConfig.enabled = true; + allowListConfig.signerPublicKey = address(0); + s_termsOfServiceAllowList.updateConfig(allowListConfig); + + // Provide garbage data (v cannot be 29) to generate an invalid signature + uint8 v = 29; + bytes32 r = 0x0101010000000000000000000000000000000000000000000000000000000000; + bytes32 s = 0x0101010000000000000000000000000000000000000000000000000000000000; + + // Expect a revert on invalid signature but the call is successful + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + // vm.expectRevert(TermsOfServiceAllowList.InvalidSignature.selector); + // TODO: Add validation to setConfig to prevent empty signer + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + } + event AddedAccess(address user); function test_AcceptTermsOfService_SuccessIfAcceptingForSelf() public { @@ -175,7 +195,14 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); - assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), true); + assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); + + // Event emitted even though adding existing item into EnumerableSet set does nothing + // TODO: handle differently in contract + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit AddedAccess(STRANGER_ADDRESS); + s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); } function test_AcceptTermsOfService_SuccessIfAcceptingForContract() public { @@ -279,6 +306,8 @@ contract FunctionsTermsOfServiceAllowList_BlockSender is FunctionsRoutesSetup { event BlockedAccess(address user); function test_BlockSender_Success() public { + assertFalse(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS)); + // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). bool checkTopic1 = false; bool checkTopic2 = false; @@ -288,8 +317,8 @@ contract FunctionsTermsOfServiceAllowList_BlockSender is FunctionsRoutesSetup { emit BlockedAccess(STRANGER_ADDRESS); s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); - assertEq(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0)), false); - assertEq(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS), true); + assertFalse(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); + assertTrue(s_termsOfServiceAllowList.isBlockedSender(STRANGER_ADDRESS)); // Account can no longer accept Terms of Service bytes32 message = s_termsOfServiceAllowList.getMessage(STRANGER_ADDRESS, STRANGER_ADDRESS); diff --git a/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol b/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol new file mode 100644 index 00000000000..55ab3810b41 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; +import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; + +import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup} from "./Setup.t.sol"; + +import "forge-std/Vm.sol"; + +/// @notice #acceptTermsOfService +contract Gas_AcceptTermsOfService is FunctionsRoutesSetup { + bytes32 s_sigR; + bytes32 s_sigS; + uint8 s_sigV; + + function setUp() public virtual override { + vm.pauseGasMetering(); + + FunctionsRoutesSetup.setUp(); + + bytes32 message = s_termsOfServiceAllowList.getMessage(OWNER_ADDRESS, OWNER_ADDRESS); + bytes32 prefixedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message)); + (s_sigV, s_sigR, s_sigS) = vm.sign(TOS_SIGNER_PRIVATE_KEY, prefixedMessage); + } + + function test_AcceptTermsOfService_Gas() public { + // Pull storage variables into memory + address ownerAddress = OWNER_ADDRESS; + bytes32 sigR = s_sigR; + bytes32 sigS = s_sigS; + uint8 sigV = s_sigV; + vm.resumeGasMetering(); + + s_termsOfServiceAllowList.acceptTermsOfService(ownerAddress, ownerAddress, sigR, sigS, sigV); + } +} + +/// @notice #createSubscription +contract Gas_CreateSubscription is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_CreateSubscription_Gas() public { + s_functionsRouter.createSubscription(); + } +} + +/// @notice #addConsumer +contract Gas_AddConsumer is FunctionsSubscriptionSetup { + function setUp() public virtual override { + vm.pauseGasMetering(); + + FunctionsSubscriptionSetup.setUp(); + } + + function test_AddConsumer_Gas() public { + // Keep input data in memory + uint64 subscriptionId = s_subscriptionId; + address consumerAddress = address(s_functionsCoordinator); // use garbage address + vm.resumeGasMetering(); + + s_functionsRouter.addConsumer(subscriptionId, consumerAddress); + } +} + +/// @notice #fundSubscription +contract Gas_FundSubscription is FunctionsSubscriptionSetup { + function setUp() public virtual override { + vm.pauseGasMetering(); + + FunctionsSubscriptionSetup.setUp(); + } + + function test_FundSubscription_Gas() public { + // Keep input data in memory + address routerAddress = address(s_functionsRouter); + uint96 s_subscriptionFunding = 10 * JUELS_PER_LINK; // 10 LINK + bytes memory data = abi.encode(s_subscriptionId); + vm.resumeGasMetering(); + + s_linkToken.transferAndCall(routerAddress, s_subscriptionFunding, data); + } +} + +/// @notice #sendRequest +contract Gas_SendRequest is FunctionsSubscriptionSetup { + bytes s_minimalRequestData; + bytes s_maximalRequestData; + + function _makeStringOfBytesSize(uint16 bytesSize) internal pure returns (string memory) { + return vm.toString(new bytes((bytesSize - 2) / 2)); + } + + function setUp() public virtual override { + vm.pauseGasMetering(); + + FunctionsSubscriptionSetup.setUp(); + + { + // Create minimum viable request data + FunctionsRequest.Request memory minimalRequest; + string memory minimalSourceCode = "return Functions.encodeString('hello world');"; + FunctionsRequest._initializeRequest( + minimalRequest, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + minimalSourceCode + ); + s_minimalRequestData = FunctionsRequest._encodeCBOR(minimalRequest); + } + + { + // Create maximum viable request data - 30 KB encoded data + FunctionsRequest.Request memory maxmimalRequest; + + // Create maximum viable request data - 30 KB encoded data + string memory maximalSourceCode = _makeStringOfBytesSize(29_898); // CBOR size without source code is 102 bytes + FunctionsRequest._initializeRequest( + maxmimalRequest, + FunctionsRequest.Location.Inline, + FunctionsRequest.CodeLanguage.JavaScript, + maximalSourceCode + ); + s_maximalRequestData = FunctionsRequest._encodeCBOR(maxmimalRequest); + assertEq(s_maximalRequestData.length, 30_000); + } + } + + /// @dev The order of these test cases matters as the first test will consume more gas by writing over default values + function test_SendRequest_MaximumGas() public { + // Pull storage variables into memory + bytes memory maximalRequestData = s_maximalRequestData; + uint64 subscriptionId = s_subscriptionId; + uint32 callbackGasLimit = 300_000; + bytes32 donId = s_donId; + vm.resumeGasMetering(); + + s_functionsClient.sendRequestBytes(maximalRequestData, subscriptionId, callbackGasLimit, donId); + } + + function test_SendRequest_MinimumGas() public { + // Pull storage variables into memory + bytes memory minimalRequestData = s_minimalRequestData; + uint64 subscriptionId = s_subscriptionId; + uint32 callbackGasLimit = 5_500; + bytes32 donId = s_donId; + vm.resumeGasMetering(); + + s_functionsClient.sendRequestBytes(minimalRequestData, subscriptionId, callbackGasLimit, donId); + } +} + +/// @notice #fulfillRequest +contract FunctionsClient_FulfillRequest is FunctionsClientRequestSetup { + struct Report { + bytes32[] rs; + bytes32[] ss; + bytes32 vs; + bytes report; + bytes32[3] reportContext; + } + + mapping(uint256 reportNumber => Report) s_reports; + + FunctionsClientTestHelper s_functionsClientWithMaximumReturnData; + + function _makeStringOfBytesSize(uint16 bytesSize) internal pure returns (string memory) { + return vm.toString(new bytes((bytesSize - 2) / 2)); + } + + function setUp() public virtual override { + vm.pauseGasMetering(); + + FunctionsSubscriptionSetup.setUp(); + + { + // Deploy consumer that has large revert return data + s_functionsClientWithMaximumReturnData = new FunctionsClientTestHelper(address(s_functionsRouter)); + s_functionsClientWithMaximumReturnData.setRevertFulfillRequest(true); + string memory revertMessage = _makeStringOfBytesSize(30_000); // 30kb - FunctionsRouter cuts off response at MAX_CALLBACK_RETURN_BYTES = 4 + 4 * 32 = 132bytes, go well above that + s_functionsClientWithMaximumReturnData.setRevertFulfillRequestMessage(revertMessage); + s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClientWithMaximumReturnData)); + } + + // Set up maximum gas test + { + // Send request #2 for maximum gas test + uint8 requestNumber = 2; + + bytes memory secrets = new bytes(0); + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + uint32 callbackGasLimit = 300_000; + + // Create maximum viable request data - 30 KB encoded data + string memory maximalSourceCode = _makeStringOfBytesSize(29_898); // CBOR size without source code is 102 bytes + + _sendAndStoreRequest( + requestNumber, + maximalSourceCode, + secrets, + args, + bytesArgs, + callbackGasLimit, + address(s_functionsClientWithMaximumReturnData) + ); + + // Build the report transmission data + uint256[] memory requestNumberKeys = new uint256[](1); + requestNumberKeys[0] = requestNumber; + string[] memory results = new string[](1); + // Build a 256 byte response size + results[0] = _makeStringOfBytesSize(256); + bytes[] memory errors = new bytes[](1); + errors[0] = new bytes(0); // No error + + (bytes memory report, bytes32[3] memory reportContext) = _buildReport(requestNumberKeys, results, errors); + + uint256[] memory signerPrivateKeys = new uint256[](3); + signerPrivateKeys[0] = NOP_SIGNER_PRIVATE_KEY_1; + signerPrivateKeys[1] = NOP_SIGNER_PRIVATE_KEY_2; + signerPrivateKeys[2] = NOP_SIGNER_PRIVATE_KEY_3; + + (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) = _signReport( + report, + reportContext, + signerPrivateKeys + ); + + // Store the report data + s_reports[1] = Report({rs: rawRs, ss: rawSs, vs: rawVs, report: report, reportContext: reportContext}); + } + + // Set up minimum gas test + { + // Send requests minimum gas test + uint8 requestsToSend = 1; + uint8 requestNumberOffset = 3; // the setup already has request #1 sent, and the previous test case uses request #2, start from request #3 + + string memory sourceCode = "return Functions.encodeString('hello world');"; + bytes memory secrets = new bytes(0); + string[] memory args = new string[](0); + bytes[] memory bytesArgs = new bytes[](0); + uint32 callbackGasLimit = 5_500; + + for (uint256 i = 0; i < requestsToSend; ++i) { + _sendAndStoreRequest(i + requestNumberOffset, sourceCode, secrets, args, bytesArgs, callbackGasLimit); + } + + // Build the report transmission data + uint256[] memory requestNumberKeys = new uint256[](requestsToSend); + string[] memory results = new string[](requestsToSend); + bytes[] memory errors = new bytes[](requestsToSend); + for (uint256 i = 0; i < requestsToSend; ++i) { + requestNumberKeys[i] = i + requestNumberOffset; + results[i] = "hello world"; + errors[i] = new bytes(0); // no error + } + + (bytes memory report, bytes32[3] memory reportContext) = _buildReport(requestNumberKeys, results, errors); + + uint256[] memory signerPrivateKeys = new uint256[](3); + signerPrivateKeys[0] = NOP_SIGNER_PRIVATE_KEY_1; + signerPrivateKeys[1] = NOP_SIGNER_PRIVATE_KEY_2; + signerPrivateKeys[2] = NOP_SIGNER_PRIVATE_KEY_3; + + (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) = _signReport( + report, + reportContext, + signerPrivateKeys + ); + + // Store the report data + s_reports[2] = Report({rs: rawRs, ss: rawSs, vs: rawVs, report: report, reportContext: reportContext}); + } + + vm.stopPrank(); + vm.startPrank(NOP_TRANSMITTER_ADDRESS_1); + } + + /// @dev The order of these test cases matters as the first test will consume more gas by writing over default values + function test_FulfillRequest_MaximumGas() public { + // Pull storage variables into memory + uint8 reportNumber = 1; + bytes32[] memory rs = s_reports[reportNumber].rs; + bytes32[] memory ss = s_reports[reportNumber].ss; + bytes32 vs = s_reports[reportNumber].vs; + bytes memory report = s_reports[reportNumber].report; + bytes32[3] memory reportContext = s_reports[reportNumber].reportContext; + vm.resumeGasMetering(); + + // 1 fulfillment in the report, single request takes on all report validation cost + // maximum request + // maximum NOPs + // maximum return data + // first storage write to change default values + s_functionsCoordinator.transmit(reportContext, report, rs, ss, vs); + } + + function test_FulfillRequest_MinimumGas() public { + // Pull storage variables into memory + uint8 reportNumber = 2; + bytes32[] memory rs = s_reports[reportNumber].rs; + bytes32[] memory ss = s_reports[reportNumber].ss; + bytes32 vs = s_reports[reportNumber].vs; + bytes memory report = s_reports[reportNumber].report; + bytes32[3] memory reportContext = s_reports[reportNumber].reportContext; + vm.resumeGasMetering(); + + // max fulfillments in the report, cost of validation split between all + // minimal request + // minimum NOPs + // no return data + // not storage writing default values + s_functionsCoordinator.transmit(reportContext, report, rs, ss, vs); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol b/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol new file mode 100644 index 00000000000..745ad4f0ae9 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/OCR2.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +// ================================================================ +// | OCR2Base | +// ================================================================ + +/// @notice #constructor +contract OCR2Base_Constructor { + +} + +/// @notice #checkConfigValid +contract OCR2Base_CheckConfigValid { + +} + +/// @notice #latestConfigDigestAndEpoch +contract OCR2Base_LatestConfigDigestAndEpoch { + +} + +/// @notice #setConfig +contract OCR2Base_SetConfig { + +} + +/// @notice #configDigestFromConfigData +contract OCR2Base_ConfigDigestFromConfigData { + +} + +/// @notice #latestConfigDetails +contract OCR2Base_LatestConfigDetails { + +} + +/// @notice #transmitters +contract OCR2Base_Transmitters { + +} + +/// @notice #_report +contract OCR2Base__Report { + // TODO: make contract internal function helper +} + +/// @notice #requireExpectedMsgDataLength +contract OCR2Base_RequireExpectedMsgDataLength { + +} + +/// @notice #transmit +contract OCR2Base_Transmit { + +} diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/README.md b/contracts/src/v0.8/functions/tests/v1_X/README.md similarity index 84% rename from contracts/src/v0.8/functions/tests/v1_0_0/README.md rename to contracts/src/v0.8/functions/tests/v1_X/README.md index 42aa6ed2b7b..6400a28dc79 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/README.md +++ b/contracts/src/v0.8/functions/tests/v1_X/README.md @@ -12,7 +12,7 @@ forge test -vv To run a specific file use: ``` -forge test -vv --mp src/v0.8/functions/tests/v1_0_0/[File Name].t.sol +forge test -vv --mp src/v0.8/functions/tests/v1_X/[File Name].t.sol ``` To see coverage: diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/Setup.t.sol b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol similarity index 93% rename from contracts/src/v0.8/functions/tests/v1_0_0/Setup.t.sol rename to contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol index 73644e38636..f603e83281c 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/Setup.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.19; import {BaseTest} from "./BaseTest.t.sol"; -import {FunctionsRouter} from "../../dev/v1_0_0/FunctionsRouter.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; import {FunctionsCoordinatorTestHelper} from "./testhelpers/FunctionsCoordinatorTestHelper.sol"; -import {FunctionsBilling} from "../../dev/v1_0_0/FunctionsBilling.sol"; -import {FunctionsResponse} from "../../dev/v1_0_0/libraries/FunctionsResponse.sol"; +import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; -import {TermsOfServiceAllowList} from "../../dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; import {FunctionsClientUpgradeHelper} from "./testhelpers/FunctionsClientUpgradeHelper.sol"; import {MockLinkToken} from "../../../mocks/MockLinkToken.sol"; @@ -74,7 +74,8 @@ contract FunctionsRouterSetup is BaseTest { donFee: s_donFee, maxSupportedRequestDataVersion: 1, fulfillmentGasPriceOverEstimationBP: 5000, - fallbackNativePerUnitLink: 5000000000000000 + fallbackNativePerUnitLink: 5000000000000000, + minimumEstimateGasPriceWei: 1000000000 // 1 gwei }); } @@ -212,7 +213,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { FunctionsResponse.Commitment commitment; } - mapping(uint256 => Request) s_requests; + mapping(uint256 requestNumber => Request) s_requests; uint96 s_fulfillmentRouterOwnerBalance = 0; uint96 s_fulfillmentCoordinatorBalance = 0; @@ -244,13 +245,15 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { /// @param args - String arguments that will be passed into the source code /// @param bytesArgs - Bytes arguments that will be passed into the source code /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param client - The consumer contract to send the request from function _sendAndStoreRequest( uint256 requestNumberKey, string memory sourceCode, bytes memory secrets, string[] memory args, bytes[] memory bytesArgs, - uint32 callbackGasLimit + uint32 callbackGasLimit, + address client ) internal { if (s_requests[requestNumberKey].requestId != bytes32(0)) { revert("Request already written"); @@ -258,7 +261,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { vm.recordLogs(); - bytes32 requestId = s_functionsClient.sendRequest( + bytes32 requestId = FunctionsClientUpgradeHelper(client).sendRequest( s_donId, sourceCode, secrets, @@ -288,11 +291,32 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { } /// @notice Send a request and store information about it in s_requests - /// @param requestNumberKeys - One or more requestNumberKeys that were used to store the request in `s_requests` of the requests, that will be added to the report - /// @param results - The result that will be sent to the consumer contract's callback. For each index, e.g. result[index] or errors[index], only one of should be filled. - /// @param errors - The error that will be sent to the consumer contract's callback. For each index, e.g. result[index] or errors[index], only one of should be filled. - /// @return report - Report bytes data - /// @return reportContext - Report context bytes32 data + /// @param requestNumberKey - the key that the request will be stored in `s_requests` in + /// @param sourceCode - Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted + /// @param secrets - Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets()) + /// @param args - String arguments that will be passed into the source code + /// @param bytesArgs - Bytes arguments that will be passed into the source code + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @dev @param client - The consumer contract to send the request from (overloaded to fill client with s_functionsClient) + function _sendAndStoreRequest( + uint256 requestNumberKey, + string memory sourceCode, + bytes memory secrets, + string[] memory args, + bytes[] memory bytesArgs, + uint32 callbackGasLimit + ) internal { + _sendAndStoreRequest( + requestNumberKey, + sourceCode, + secrets, + args, + bytesArgs, + callbackGasLimit, + address(s_functionsClient) + ); + } + function _buildReport( uint256[] memory requestNumberKeys, string[] memory results, diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol similarity index 65% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientTestHelper.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol index 987bf3e48ab..bca0f0a3fa2 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import {ITermsOfServiceAllowList} from "../../../dev/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol"; -import {IFunctionsSubscriptions} from "../../../dev/v1_0_0/interfaces/IFunctionsSubscriptions.sol"; +import {ITermsOfServiceAllowList} from "../../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; +import {IFunctionsSubscriptions} from "../../../dev/v1_X/interfaces/IFunctionsSubscriptions.sol"; -import {FunctionsRequest} from "../../../dev/v1_0_0/libraries/FunctionsRequest.sol"; -import {FunctionsClient} from "../../../dev/v1_0_0/FunctionsClient.sol"; +import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; contract FunctionsClientTestHelper is FunctionsClient { using FunctionsRequest for FunctionsRequest.Request; @@ -14,6 +14,7 @@ contract FunctionsClientTestHelper is FunctionsClient { event FulfillRequestInvoked(bytes32 requestId, bytes response, bytes err); bool private s_revertFulfillRequest; + string private s_revertFulfillRequestMessage = "asked to revert"; bool private s_doInvalidOperation; bool private s_doInvalidReentrantOperation; bool private s_doValidReentrantOperation; @@ -23,6 +24,24 @@ contract FunctionsClientTestHelper is FunctionsClient { constructor(address router) FunctionsClient(router) {} + function sendRequest( + bytes32 donId, + string calldata source, + bytes calldata secrets, + string[] calldata args, + bytes[] memory bytesArgs, + uint64 subscriptionId, + uint32 callbackGasLimit + ) public returns (bytes32 requestId) { + FunctionsRequest.Request memory req; + req._initializeRequestForInlineJavaScript(source); + if (secrets.length > 0) req._addSecretsReference(secrets); + if (args.length > 0) req._setArgs(args); + if (bytesArgs.length > 0) req._setBytesArgs(bytesArgs); + + return _sendRequest(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + } + function sendSimpleRequestWithJavaScript( string memory sourceCode, uint64 subscriptionId, @@ -30,8 +49,8 @@ contract FunctionsClientTestHelper is FunctionsClient { uint32 callbackGasLimit ) public returns (bytes32 requestId) { FunctionsRequest.Request memory request; - request.initializeRequestForInlineJavaScript(sourceCode); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + request._initializeRequestForInlineJavaScript(sourceCode); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); requestId = _sendRequest(requestData, subscriptionId, callbackGasLimit, donId); emit SendRequestInvoked(requestId, sourceCode, subscriptionId); } @@ -43,8 +62,8 @@ contract FunctionsClientTestHelper is FunctionsClient { ) public returns (bytes32 requestId) { FunctionsRequest.Request memory request; uint32 callbackGasLimit = 20_000; - request.initializeRequestForInlineJavaScript(sourceCode); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + request._initializeRequestForInlineJavaScript(sourceCode); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); requestId = i_router.sendRequestToProposed( subscriptionId, requestData, @@ -66,9 +85,9 @@ contract FunctionsClientTestHelper is FunctionsClient { IFunctionsSubscriptions(address(i_router)).acceptSubscriptionOwnerTransfer(subscriptionId); } - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { if (s_revertFulfillRequest) { - revert("asked to revert"); + revert(s_revertFulfillRequestMessage); } if (s_doInvalidOperation) { uint256 x = 1; @@ -88,6 +107,10 @@ contract FunctionsClientTestHelper is FunctionsClient { s_revertFulfillRequest = on; } + function setRevertFulfillRequestMessage(string memory message) external { + s_revertFulfillRequestMessage = message; + } + function setDoInvalidOperation(bool on) external { s_doInvalidOperation = on; } diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientUpgradeHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol similarity index 70% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientUpgradeHelper.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol index e04ead8ad83..a52c3009927 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientUpgradeHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientUpgradeHelper.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {FunctionsRequest} from "../../../dev/v1_0_0/libraries/FunctionsRequest.sol"; -import {FunctionsClient} from "../../../dev/v1_0_0/FunctionsClient.sol"; +import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { @@ -33,12 +33,21 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - if (secrets.length > 0) req.addSecretsReference(secrets); - if (args.length > 0) req.setArgs(args); - if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); + req._initializeRequestForInlineJavaScript(source); + if (secrets.length > 0) req._addSecretsReference(secrets); + if (args.length > 0) req._setArgs(args); + if (bytesArgs.length > 0) req._setBytesArgs(bytesArgs); - return _sendRequest(FunctionsRequest.encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + return _sendRequest(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + } + + function sendRequestBytes( + bytes memory data, + uint64 subscriptionId, + uint32 callbackGasLimit, + bytes32 donId + ) public returns (bytes32 requestId) { + return _sendRequest(data, subscriptionId, callbackGasLimit, donId); } /** @@ -54,12 +63,12 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - req.addDONHostedSecrets(slotId, slotVersion); + req._initializeRequestForInlineJavaScript(source); + req._addDONHostedSecrets(slotId, slotVersion); - if (args.length > 0) req.setArgs(args); + if (args.length > 0) req._setArgs(args); - return _sendRequest(FunctionsRequest.encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + return _sendRequest(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } // @notice Sends a Chainlink Functions request @@ -105,12 +114,12 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - if (secrets.length > 0) req.addSecretsReference(secrets); - if (args.length > 0) req.setArgs(args); - if (bytesArgs.length > 0) req.setBytesArgs(bytesArgs); + req._initializeRequestForInlineJavaScript(source); + if (secrets.length > 0) req._addSecretsReference(secrets); + if (args.length > 0) req._setArgs(args); + if (bytesArgs.length > 0) req._setBytesArgs(bytesArgs); - return _sendRequestToProposed(FunctionsRequest.encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + return _sendRequestToProposed(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } /** @@ -126,12 +135,12 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { uint32 callbackGasLimit ) public onlyOwner returns (bytes32) { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - req.addDONHostedSecrets(slotId, slotVersion); + req._initializeRequestForInlineJavaScript(source); + req._addDONHostedSecrets(slotId, slotVersion); - if (args.length > 0) req.setArgs(args); + if (args.length > 0) req._setArgs(args); - return _sendRequestToProposed(FunctionsRequest.encodeCBOR(req), subscriptionId, callbackGasLimit, donId); + return _sendRequestToProposed(FunctionsRequest._encodeCBOR(req), subscriptionId, callbackGasLimit, donId); } /** @@ -142,7 +151,7 @@ contract FunctionsClientUpgradeHelper is FunctionsClient, ConfirmedOwner { * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { emit ResponseReceived(requestId, response, err); } } diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientWithEmptyCallback.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol similarity index 66% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientWithEmptyCallback.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol index 5feede895f0..362b21d89ba 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientWithEmptyCallback.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import {FunctionsRequest} from "../../../dev/v1_0_0/libraries/FunctionsRequest.sol"; -import {FunctionsClient} from "../../../dev/v1_0_0/FunctionsClient.sol"; +import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; contract FunctionsClientWithEmptyCallback is FunctionsClient { using FunctionsRequest for FunctionsRequest.Request; @@ -19,13 +19,13 @@ contract FunctionsClientWithEmptyCallback is FunctionsClient { uint32 callbackGasLimit ) public returns (bytes32 requestId) { FunctionsRequest.Request memory request; - request.initializeRequestForInlineJavaScript(sourceCode); - bytes memory requestData = FunctionsRequest.encodeCBOR(request); + request._initializeRequestForInlineJavaScript(sourceCode); + bytes memory requestData = FunctionsRequest._encodeCBOR(request); requestId = _sendRequest(requestData, subscriptionId, callbackGasLimit, donId); emit SendRequestInvoked(requestId, sourceCode, subscriptionId); } - function fulfillRequest(bytes32 /*requestId*/, bytes memory /*response*/, bytes memory /*err*/) internal override { + function _fulfillRequest(bytes32 /*requestId*/, bytes memory /*response*/, bytes memory /*err*/) internal override { // Do nothing } } diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol similarity index 85% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol index bf55258fbdb..1d883b3b29a 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import {FunctionsCoordinator} from "../../../dev/v1_0_0/FunctionsCoordinator.sol"; -import {FunctionsBilling} from "../../../dev/v1_0_0/FunctionsBilling.sol"; +import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; +import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; contract FunctionsCoordinatorTestHelper is FunctionsCoordinator { constructor( diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsLoadTestClient.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsLoadTestClient.sol similarity index 83% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsLoadTestClient.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsLoadTestClient.sol index c31962ba1f4..1623fc5e124 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsLoadTestClient.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsLoadTestClient.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {FunctionsClient} from "../../../dev/v1_0_0/FunctionsClient.sol"; +import {FunctionsClient} from "../../../dev/v1_X/FunctionsClient.sol"; import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; -import {FunctionsRequest} from "../../../dev/v1_0_0/libraries/FunctionsRequest.sol"; +import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; /** * @title Chainlink Functions load test client implementation @@ -41,12 +41,12 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { bytes32 donId ) external onlyOwner { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - if (encryptedSecretsReferences.length > 0) req.addSecretsReference(encryptedSecretsReferences); - if (args.length > 0) req.setArgs(args); + req._initializeRequestForInlineJavaScript(source); + if (encryptedSecretsReferences.length > 0) req._addSecretsReference(encryptedSecretsReferences); + if (args.length > 0) req._setArgs(args); uint i = 0; for (i = 0; i < times; i++) { - lastRequestID = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); + lastRequestID = _sendRequest(req._encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); totalRequests += 1; } } @@ -71,12 +71,12 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { bytes32 donId ) public onlyOwner { FunctionsRequest.Request memory req; - req.initializeRequestForInlineJavaScript(source); - req.addDONHostedSecrets(slotId, slotVersion); - if (args.length > 0) req.setArgs(args); + req._initializeRequestForInlineJavaScript(source); + req._addDONHostedSecrets(slotId, slotVersion); + if (args.length > 0) req._setArgs(args); uint i = 0; for (i = 0; i < times; i++) { - lastRequestID = _sendRequest(req.encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); + lastRequestID = _sendRequest(req._encodeCBOR(), subscriptionId, MAX_CALLBACK_GAS, donId); totalRequests += 1; } } @@ -135,7 +135,7 @@ contract FunctionsLoadTestClient is FunctionsClient, ConfirmedOwner { * @param err Aggregated error from the user code or from the execution pipeline * Either response or error parameter will be set, but never both */ - function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { + function _fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override { lastRequestID = requestId; lastResponse = response; lastError = err; diff --git a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol similarity index 81% rename from contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsTestHelper.sol rename to contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol index 9ab5386dda7..e8e74e3ed74 100644 --- a/contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import {FunctionsRequest} from "../../../dev/v1_0_0/libraries/FunctionsRequest.sol"; +import {FunctionsRequest} from "../../../dev/v1_X/libraries/FunctionsRequest.sol"; contract FunctionsTestHelper { using FunctionsRequest for FunctionsRequest.Request; @@ -11,25 +11,25 @@ contract FunctionsTestHelper { event RequestData(bytes data); function closeEvent() public { - emit RequestData(s_req.encodeCBOR()); + emit RequestData(s_req._encodeCBOR()); } function initializeRequestForInlineJavaScript(string memory sourceCode) public { FunctionsRequest.Request memory r; - r.initializeRequestForInlineJavaScript(sourceCode); + r._initializeRequestForInlineJavaScript(sourceCode); storeRequest(r); } function addSecretsReference(bytes memory secrets) public { FunctionsRequest.Request memory r = s_req; - r.addSecretsReference(secrets); + r._addSecretsReference(secrets); storeRequest(r); } function addEmptyArgs() public pure { FunctionsRequest.Request memory r; string[] memory args; - r.setArgs(args); + r._setArgs(args); } function addTwoArgs(string memory arg1, string memory arg2) public { @@ -37,7 +37,7 @@ contract FunctionsTestHelper { args[0] = arg1; args[1] = arg2; FunctionsRequest.Request memory r = s_req; - r.setArgs(args); + r._setArgs(args); storeRequest(r); } diff --git a/contracts/src/v0.8/functions/v1_0_0/.gitkeep b/contracts/src/v0.8/functions/v1_0_0/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsBilling.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol similarity index 98% rename from contracts/src/v0.8/functions/dev/v1_0_0/FunctionsBilling.sol rename to contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol index c616f7355d2..1f99903c5a2 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsBilling.sol @@ -2,17 +2,16 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; -import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; -import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). -/// @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. abstract contract FunctionsBilling is Routable, IFunctionsBilling { using FunctionsResponse for FunctionsResponse.RequestMeta; using FunctionsResponse for FunctionsResponse.Commitment; diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsClient.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol similarity index 100% rename from contracts/src/v0.8/functions/dev/v1_0_0/FunctionsClient.sol rename to contracts/src/v0.8/functions/v1_0_0/FunctionsClient.sol diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsCoordinator.sol new file mode 100644 index 00000000000..1488bc45888 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsCoordinator.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; + +import {FunctionsBilling} from "./FunctionsBilling.sol"; +import {OCR2Base} from "./ocr/OCR2Base.sol"; +import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; + +/// @title Functions Coordinator contract +/// @notice Contract that nodes of a Decentralized Oracle Network (DON) interact with +contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilling { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + /// @inheritdoc ITypeAndVersion + string public constant override typeAndVersion = "Functions Coordinator v1.0.0"; + + event OracleRequest( + bytes32 indexed requestId, + address indexed requestingContract, + address requestInitiator, + uint64 subscriptionId, + address subscriptionOwner, + bytes data, + uint16 dataVersion, + bytes32 flags, + uint64 callbackGasLimit, + FunctionsResponse.Commitment commitment + ); + event OracleResponse(bytes32 indexed requestId, address transmitter); + + error InconsistentReportData(); + error EmptyPublicKey(); + error UnauthorizedPublicKeyChange(); + + bytes private s_donPublicKey; + bytes private s_thresholdPublicKey; + + constructor( + address router, + Config memory config, + address linkToNativeFeed + ) OCR2Base(true) FunctionsBilling(router, config, linkToNativeFeed) {} + + /// @inheritdoc IFunctionsCoordinator + function getThresholdPublicKey() external view override returns (bytes memory) { + if (s_thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setThresholdPublicKey(bytes calldata thresholdPublicKey) external override onlyOwner { + if (thresholdPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_thresholdPublicKey = thresholdPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function getDONPublicKey() external view override returns (bytes memory) { + if (s_donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + return s_donPublicKey; + } + + /// @inheritdoc IFunctionsCoordinator + function setDONPublicKey(bytes calldata donPublicKey) external override onlyOwner { + if (donPublicKey.length == 0) { + revert EmptyPublicKey(); + } + s_donPublicKey = donPublicKey; + } + + /// @dev check if node is in current transmitter list + function _isTransmitter(address node) internal view returns (bool) { + address[] memory nodes = s_transmitters; + // Bounded by "maxNumOracles" on OCR2Abstract.sol + for (uint256 i = 0; i < nodes.length; ++i) { + if (nodes[i] == node) { + return true; + } + } + return false; + } + + /// @inheritdoc IFunctionsCoordinator + function startRequest( + FunctionsResponse.RequestMeta calldata request + ) external override onlyRouter returns (FunctionsResponse.Commitment memory commitment) { + commitment = _startBilling(request); + + emit OracleRequest( + commitment.requestId, + request.requestingContract, + tx.origin, + request.subscriptionId, + request.subscriptionOwner, + request.data, + request.dataVersion, + request.flags, + request.callbackGasLimit, + commitment + ); + + return commitment; + } + + /// @dev DON fees are pooled together. If the OCR configuration is going to change, these need to be distributed. + function _beforeSetConfig(uint8 /* _f */, bytes memory /* _onchainConfig */) internal override { + if (_getTransmitters().length > 0) { + _disperseFeePool(); + } + } + + /// @dev Used by FunctionsBilling.sol + function _getTransmitters() internal view override returns (address[] memory) { + return s_transmitters; + } + + /// @dev Report hook called within OCR2Base.sol + function _report( + uint256 /*initialGas*/, + address /*transmitter*/, + uint8 /*signerCount*/, + address[MAX_NUM_ORACLES] memory /*signers*/, + bytes calldata report + ) internal override { + bytes32[] memory requestIds; + bytes[] memory results; + bytes[] memory errors; + bytes[] memory onchainMetadata; + bytes[] memory offchainMetadata; + (requestIds, results, errors, onchainMetadata, offchainMetadata) = abi.decode( + report, + (bytes32[], bytes[], bytes[], bytes[], bytes[]) + ); + + if ( + requestIds.length == 0 || + requestIds.length != results.length || + requestIds.length != errors.length || + requestIds.length != onchainMetadata.length || + requestIds.length != offchainMetadata.length + ) { + revert ReportInvalid(); + } + + // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig + for (uint256 i = 0; i < requestIds.length; ++i) { + FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( + _fulfillAndBill(requestIds[i], results[i], errors[i], onchainMetadata[i], offchainMetadata[i]) + ); + + // Emit on successfully processing the fulfillment + // In these two fulfillment results the user has been charged + // Otherwise, the DON will re-try + if ( + result == FunctionsResponse.FulfillResult.FULFILLED || + result == FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR + ) { + emit OracleResponse(requestIds[i], msg.sender); + } + } + } + + /// @dev Used in FunctionsBilling.sol + function _onlyOwner() internal view override { + _validateOwnership(); + } +} diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol new file mode 100644 index 00000000000..dad50b042b9 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsRouter.sol @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol"; +import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; +import {IAccessController} from "../../shared/interfaces/IAccessController.sol"; + +import {FunctionsSubscriptions} from "./FunctionsSubscriptions.sol"; +import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; + +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; +import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/security/Pausable.sol"; + +contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, ITypeAndVersion, ConfirmedOwner { + using FunctionsResponse for FunctionsResponse.RequestMeta; + using FunctionsResponse for FunctionsResponse.Commitment; + using FunctionsResponse for FunctionsResponse.FulfillResult; + + string public constant override typeAndVersion = "Functions Router v1.0.0"; + + // We limit return data to a selector plus 4 words. This is to avoid + // malicious contracts from returning large amounts of data and causing + // repeated out-of-gas scenarios. + uint16 public constant MAX_CALLBACK_RETURN_BYTES = 4 + 4 * 32; + uint8 private constant MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX = 0; + + event RequestStart( + bytes32 indexed requestId, + bytes32 indexed donId, + uint64 indexed subscriptionId, + address subscriptionOwner, + address requestingContract, + address requestInitiator, + bytes data, + uint16 dataVersion, + uint32 callbackGasLimit, + uint96 estimatedTotalCostJuels + ); + + event RequestProcessed( + bytes32 indexed requestId, + uint64 indexed subscriptionId, + uint96 totalCostJuels, + address transmitter, + FunctionsResponse.FulfillResult resultCode, + bytes response, + bytes err, + bytes callbackReturnData + ); + + event RequestNotProcessed( + bytes32 indexed requestId, + address coordinator, + address transmitter, + FunctionsResponse.FulfillResult resultCode + ); + + error EmptyRequestData(); + error OnlyCallableFromCoordinator(); + error SenderMustAcceptTermsOfService(address sender); + error InvalidGasFlagValue(uint8 value); + error GasLimitTooBig(uint32 limit); + error DuplicateRequestId(bytes32 requestId); + + struct CallbackResult { + bool success; // ══════╸ Whether the callback succeeded or not + uint256 gasUsed; // ═══╸ The amount of gas consumed during the callback + bytes returnData; // ══╸ The return of the callback function + } + + // ================================================================ + // | Route state | + // ================================================================ + + mapping(bytes32 id => address routableContract) private s_route; + + error RouteNotFound(bytes32 id); + + // Identifier for the route to the Terms of Service Allow List + bytes32 private s_allowListId; + + // ================================================================ + // | Configuration state | + // ================================================================ + struct Config { + uint16 maxConsumersPerSubscription; // ═════════╗ Maximum number of consumers which can be added to a single subscription. This bound ensures we are able to loop over all subscription consumers as needed, without exceeding gas limits. Should a user require more consumers, they can use multiple subscriptions. + uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract + uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. + uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. + uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. + } + + Config private s_config; + + event ConfigUpdated(Config); + + // ================================================================ + // | Proposal state | + // ================================================================ + + uint8 private constant MAX_PROPOSAL_SET_LENGTH = 8; + + struct ContractProposalSet { + bytes32[] ids; // ══╸ The IDs that key into the routes that will be modified if the update is applied + address[] to; // ═══╸ The address of the contracts that the route will point to if the updated is applied + } + ContractProposalSet private s_proposedContractSet; + + event ContractProposed( + bytes32 proposedContractSetId, + address proposedContractSetFromAddress, + address proposedContractSetToAddress + ); + + event ContractUpdated(bytes32 id, address from, address to); + + error InvalidProposal(); + error IdentifierIsReserved(bytes32 id); + + // ================================================================ + // | Initialization | + // ================================================================ + + constructor( + address linkToken, + Config memory config + ) FunctionsSubscriptions(linkToken) ConfirmedOwner(msg.sender) Pausable() { + // Set the intial configuration + updateConfig(config); + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice The identifier of the route to retrieve the address of the access control contract + // The access control contract controls which accounts can manage subscriptions + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router + function getConfig() external view returns (Config memory) { + return s_config; + } + + /// @notice The router configuration + function updateConfig(Config memory config) public onlyOwner { + s_config = config; + emit ConfigUpdated(config); + } + + /// @inheritdoc IFunctionsRouter + function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) public view { + uint8 callbackGasLimitsIndexSelector = uint8(getFlags(subscriptionId)[MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX]); + if (callbackGasLimitsIndexSelector >= s_config.maxCallbackGasLimits.length) { + revert InvalidGasFlagValue(callbackGasLimitsIndexSelector); + } + uint32 maxCallbackGasLimit = s_config.maxCallbackGasLimits[callbackGasLimitsIndexSelector]; + if (callbackGasLimit > maxCallbackGasLimit) { + revert GasLimitTooBig(maxCallbackGasLimit); + } + } + + /// @inheritdoc IFunctionsRouter + function getAdminFee() external view override returns (uint72) { + return s_config.adminFee; + } + + /// @inheritdoc IFunctionsRouter + function getAllowListId() external view override returns (bytes32) { + return s_allowListId; + } + + /// @inheritdoc IFunctionsRouter + function setAllowListId(bytes32 allowListId) external override onlyOwner { + s_allowListId = allowListId; + } + + /// @dev Used within FunctionsSubscriptions.sol + function _getMaxConsumers() internal view override returns (uint16) { + return s_config.maxConsumersPerSubscription; + } + + /// @dev Used within FunctionsSubscriptions.sol + function _getSubscriptionDepositDetails() internal view override returns (uint16, uint72) { + return (s_config.subscriptionDepositMinimumRequests, s_config.subscriptionDepositJuels); + } + + // ================================================================ + // | Requests | + // ================================================================ + + /// @inheritdoc IFunctionsRouter + function sendRequest( + uint64 subscriptionId, + bytes calldata data, + uint16 dataVersion, + uint32 callbackGasLimit, + bytes32 donId + ) external override returns (bytes32) { + IFunctionsCoordinator coordinator = IFunctionsCoordinator(getContractById(donId)); + return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); + } + + /// @inheritdoc IFunctionsRouter + function sendRequestToProposed( + uint64 subscriptionId, + bytes calldata data, + uint16 dataVersion, + uint32 callbackGasLimit, + bytes32 donId + ) external override returns (bytes32) { + IFunctionsCoordinator coordinator = IFunctionsCoordinator(getProposedContractById(donId)); + return _sendRequest(donId, coordinator, subscriptionId, data, dataVersion, callbackGasLimit); + } + + function _sendRequest( + bytes32 donId, + IFunctionsCoordinator coordinator, + uint64 subscriptionId, + bytes memory data, + uint16 dataVersion, + uint32 callbackGasLimit + ) private returns (bytes32) { + _whenNotPaused(); + _isExistingSubscription(subscriptionId); + _isAllowedConsumer(msg.sender, subscriptionId); + isValidCallbackGasLimit(subscriptionId, callbackGasLimit); + + if (data.length == 0) { + revert EmptyRequestData(); + } + + Subscription memory subscription = getSubscription(subscriptionId); + Consumer memory consumer = getConsumer(msg.sender, subscriptionId); + uint72 adminFee = s_config.adminFee; + + // Forward request to DON + FunctionsResponse.Commitment memory commitment = coordinator.startRequest( + FunctionsResponse.RequestMeta({ + requestingContract: msg.sender, + data: data, + subscriptionId: subscriptionId, + dataVersion: dataVersion, + flags: getFlags(subscriptionId), + callbackGasLimit: callbackGasLimit, + adminFee: adminFee, + initiatedRequests: consumer.initiatedRequests, + completedRequests: consumer.completedRequests, + availableBalance: subscription.balance - subscription.blockedBalance, + subscriptionOwner: subscription.owner + }) + ); + + // Do not allow setting a comittment for a requestId that already exists + if (s_requestCommitments[commitment.requestId] != bytes32(0)) { + revert DuplicateRequestId(commitment.requestId); + } + + // Store a commitment about the request + s_requestCommitments[commitment.requestId] = keccak256( + abi.encode( + FunctionsResponse.Commitment({ + adminFee: adminFee, + coordinator: address(coordinator), + client: msg.sender, + subscriptionId: subscriptionId, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: commitment.estimatedTotalCostJuels, + timeoutTimestamp: commitment.timeoutTimestamp, + requestId: commitment.requestId, + donFee: commitment.donFee, + gasOverheadBeforeCallback: commitment.gasOverheadBeforeCallback, + gasOverheadAfterCallback: commitment.gasOverheadAfterCallback + }) + ) + ); + + _markRequestInFlight(msg.sender, subscriptionId, commitment.estimatedTotalCostJuels); + + emit RequestStart({ + requestId: commitment.requestId, + donId: donId, + subscriptionId: subscriptionId, + subscriptionOwner: subscription.owner, + requestingContract: msg.sender, + requestInitiator: tx.origin, + data: data, + dataVersion: dataVersion, + callbackGasLimit: callbackGasLimit, + estimatedTotalCostJuels: commitment.estimatedTotalCostJuels + }); + + return commitment.requestId; + } + + // ================================================================ + // | Responses | + // ================================================================ + + /// @inheritdoc IFunctionsRouter + function fulfill( + bytes memory response, + bytes memory err, + uint96 juelsPerGas, + uint96 costWithoutCallback, + address transmitter, + FunctionsResponse.Commitment memory commitment + ) external override returns (FunctionsResponse.FulfillResult resultCode, uint96) { + _whenNotPaused(); + + if (msg.sender != commitment.coordinator) { + revert OnlyCallableFromCoordinator(); + } + + { + bytes32 commitmentHash = s_requestCommitments[commitment.requestId]; + + if (commitmentHash == bytes32(0)) { + resultCode = FunctionsResponse.FulfillResult.INVALID_REQUEST_ID; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + + if (keccak256(abi.encode(commitment)) != commitmentHash) { + resultCode = FunctionsResponse.FulfillResult.INVALID_COMMITMENT; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + + // Check that the transmitter has supplied enough gas for the callback to succeed + if (gasleft() < commitment.callbackGasLimit + commitment.gasOverheadAfterCallback) { + resultCode = FunctionsResponse.FulfillResult.INSUFFICIENT_GAS_PROVIDED; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + } + + { + uint96 callbackCost = juelsPerGas * SafeCast.toUint96(commitment.callbackGasLimit); + uint96 totalCostJuels = commitment.adminFee + costWithoutCallback + callbackCost; + + // Check that the subscription can still afford to fulfill the request + if (totalCostJuels > getSubscription(commitment.subscriptionId).balance) { + resultCode = FunctionsResponse.FulfillResult.SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + + // Check that the cost has not exceeded the quoted cost + if (totalCostJuels > commitment.estimatedTotalCostJuels) { + resultCode = FunctionsResponse.FulfillResult.COST_EXCEEDS_COMMITMENT; + emit RequestNotProcessed(commitment.requestId, commitment.coordinator, transmitter, resultCode); + return (resultCode, 0); + } + } + + delete s_requestCommitments[commitment.requestId]; + + CallbackResult memory result = _callback( + commitment.requestId, + response, + err, + commitment.callbackGasLimit, + commitment.client + ); + + resultCode = result.success + ? FunctionsResponse.FulfillResult.FULFILLED + : FunctionsResponse.FulfillResult.USER_CALLBACK_ERROR; + + Receipt memory receipt = _pay( + commitment.subscriptionId, + commitment.estimatedTotalCostJuels, + commitment.client, + commitment.adminFee, + juelsPerGas, + SafeCast.toUint96(result.gasUsed), + costWithoutCallback + ); + + emit RequestProcessed({ + requestId: commitment.requestId, + subscriptionId: commitment.subscriptionId, + totalCostJuels: receipt.totalCostJuels, + transmitter: transmitter, + resultCode: resultCode, + response: response, + err: err, + callbackReturnData: result.returnData + }); + + return (resultCode, receipt.callbackGasCostJuels); + } + + function _callback( + bytes32 requestId, + bytes memory response, + bytes memory err, + uint32 callbackGasLimit, + address client + ) private returns (CallbackResult memory) { + bool destinationNoLongerExists; + assembly { + // solidity calls check that a contract actually exists at the destination, so we do the same + destinationNoLongerExists := iszero(extcodesize(client)) + } + if (destinationNoLongerExists) { + // Return without attempting callback + // The subscription will still be charged to reimburse transmitter's gas overhead + return CallbackResult({success: false, gasUsed: 0, returnData: new bytes(0)}); + } + + bytes memory encodedCallback = abi.encodeWithSelector( + s_config.handleOracleFulfillmentSelector, + requestId, + response, + err + ); + + uint16 gasForCallExactCheck = s_config.gasForCallExactCheck; + + // Call with explicitly the amount of callback gas requested + // Important to not let them exhaust the gas budget and avoid payment. + // NOTE: that callWithExactGas will revert if we do not have sufficient gas + // to give the callee their requested amount. + + bool success; + uint256 gasUsed; + // allocate return data memory ahead of time + bytes memory returnData = new bytes(MAX_CALLBACK_RETURN_BYTES); + + assembly { + let g := gas() + // Compute g -= gasForCallExactCheck and check for underflow + // The gas actually passed to the callee is _min(gasAmount, 63//64*gas available). + // We want to ensure that we revert if gasAmount > 63//64*gas available + // as we do not want to provide them with less, however that check itself costs + // gas. gasForCallExactCheck ensures we have at least enough gas to be able + // to revert if gasAmount > 63//64*gas available. + if lt(g, gasForCallExactCheck) { + revert(0, 0) + } + g := sub(g, gasForCallExactCheck) + // if g - g//64 <= gasAmount, revert + // (we subtract g//64 because of EIP-150) + if iszero(gt(sub(g, div(g, 64)), callbackGasLimit)) { + revert(0, 0) + } + // call and report whether we succeeded + // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) + let gasBeforeCall := gas() + success := call(callbackGasLimit, client, 0, add(encodedCallback, 0x20), mload(encodedCallback), 0, 0) + gasUsed := sub(gasBeforeCall, gas()) + + // limit our copy to MAX_CALLBACK_RETURN_BYTES bytes + let toCopy := returndatasize() + if gt(toCopy, MAX_CALLBACK_RETURN_BYTES) { + toCopy := MAX_CALLBACK_RETURN_BYTES + } + // Store the length of the copied bytes + mstore(returnData, toCopy) + // copy the bytes from returnData[0:_toCopy] + returndatacopy(add(returnData, 0x20), 0, toCopy) + } + + return CallbackResult({success: success, gasUsed: gasUsed, returnData: returnData}); + } + + // ================================================================ + // | Route methods | + // ================================================================ + + /// @inheritdoc IFunctionsRouter + function getContractById(bytes32 id) public view override returns (address) { + address currentImplementation = s_route[id]; + if (currentImplementation == address(0)) { + revert RouteNotFound(id); + } + return currentImplementation; + } + + /// @inheritdoc IFunctionsRouter + function getProposedContractById(bytes32 id) public view override returns (address) { + // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH + for (uint8 i = 0; i < s_proposedContractSet.ids.length; ++i) { + if (id == s_proposedContractSet.ids[i]) { + return s_proposedContractSet.to[i]; + } + } + revert RouteNotFound(id); + } + + // ================================================================ + // | Contract Proposal methods | + // ================================================================ + + /// @inheritdoc IFunctionsRouter + function getProposedContractSet() external view override returns (bytes32[] memory, address[] memory) { + return (s_proposedContractSet.ids, s_proposedContractSet.to); + } + + /// @inheritdoc IFunctionsRouter + function proposeContractsUpdate( + bytes32[] memory proposedContractSetIds, + address[] memory proposedContractSetAddresses + ) external override onlyOwner { + // IDs and addresses arrays must be of equal length and must not exceed the max proposal length + uint256 idsArrayLength = proposedContractSetIds.length; + if (idsArrayLength != proposedContractSetAddresses.length || idsArrayLength > MAX_PROPOSAL_SET_LENGTH) { + revert InvalidProposal(); + } + + // NOTE: iterations of this loop will not exceed MAX_PROPOSAL_SET_LENGTH + for (uint256 i = 0; i < idsArrayLength; ++i) { + bytes32 id = proposedContractSetIds[i]; + address proposedContract = proposedContractSetAddresses[i]; + if ( + proposedContract == address(0) || // The Proposed address must be a valid address + s_route[id] == proposedContract // The Proposed address must point to a different address than what is currently set + ) { + revert InvalidProposal(); + } + + emit ContractProposed({ + proposedContractSetId: id, + proposedContractSetFromAddress: s_route[id], + proposedContractSetToAddress: proposedContract + }); + } + + s_proposedContractSet = ContractProposalSet({ids: proposedContractSetIds, to: proposedContractSetAddresses}); + } + + /// @inheritdoc IFunctionsRouter + function updateContracts() external override onlyOwner { + // Iterations will not exceed MAX_PROPOSAL_SET_LENGTH + for (uint256 i = 0; i < s_proposedContractSet.ids.length; ++i) { + bytes32 id = s_proposedContractSet.ids[i]; + address to = s_proposedContractSet.to[i]; + emit ContractUpdated({id: id, from: s_route[id], to: to}); + s_route[id] = to; + } + + delete s_proposedContractSet; + } + + // ================================================================ + // | Modifiers | + // ================================================================ + // Favoring internal functions over actual modifiers to reduce contract size + + /// @dev Used within FunctionsSubscriptions.sol + function _whenNotPaused() internal view override { + _requireNotPaused(); + } + + /// @dev Used within FunctionsSubscriptions.sol + function _onlyRouterOwner() internal view override { + _validateOwnership(); + } + + /// @dev Used within FunctionsSubscriptions.sol + function _onlySenderThatAcceptedToS() internal view override { + address currentImplementation = s_route[s_allowListId]; + if (currentImplementation == address(0)) { + // If not set, ignore this check, allow all access + return; + } + if (!IAccessController(currentImplementation).hasAccess(msg.sender, new bytes(0))) { + revert SenderMustAcceptTermsOfService(msg.sender); + } + } + + /// @inheritdoc IFunctionsRouter + function pause() external override onlyOwner { + _pause(); + } + + /// @inheritdoc IFunctionsRouter + function unpause() external override onlyOwner { + _unpause(); + } +} diff --git a/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol b/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol new file mode 100644 index 00000000000..7fa2368c46d --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/FunctionsSubscriptions.sol @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; +import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; + +import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; + +import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @title Functions Subscriptions contract +/// @notice Contract that coordinates payment from users to the nodes of the Decentralized Oracle Network (DON). +abstract contract FunctionsSubscriptions is IFunctionsSubscriptions, IERC677Receiver { + using SafeERC20 for IERC20; + using FunctionsResponse for FunctionsResponse.Commitment; + + // ================================================================ + // | Balance state | + // ================================================================ + // link token address + IERC20 internal immutable i_linkToken; + + // s_totalLinkBalance tracks the total LINK sent to/from + // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. + // A discrepancy with this contract's LINK balance indicates that someone + // sent tokens using transfer and so we may need to use recoverFunds. + uint96 private s_totalLinkBalance; + + /// @dev NOP balances are held as a single amount. The breakdown is held by the Coordinator. + mapping(address coordinator => uint96 balanceJuelsLink) private s_withdrawableTokens; + + // ================================================================ + // | Subscription state | + // ================================================================ + // Keep a count of the number of subscriptions so that its possible to + // loop through all the current subscriptions via .getSubscription(). + uint64 private s_currentSubscriptionId; + + mapping(uint64 subscriptionId => Subscription) private s_subscriptions; + + // Maintains the list of keys in s_consumers. + // We do this for 2 reasons: + // 1. To be able to clean up all keys from s_consumers when canceling a subscription. + // 2. To be able to return the list of all consumers in getSubscription. + // Note that we need the s_consumers map to be able to directly check if a + // consumer is valid without reading all the consumers from storage. + mapping(address consumer => mapping(uint64 subscriptionId => Consumer)) private s_consumers; + + event SubscriptionCreated(uint64 indexed subscriptionId, address owner); + event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); + event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); + event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); + event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); + event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); + event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); + + error TooManyConsumers(uint16 maximumConsumers); + error InsufficientBalance(uint96 currentBalanceJuels); + error InvalidConsumer(); + error CannotRemoveWithPendingRequests(); + error InvalidSubscription(); + error OnlyCallableFromLink(); + error InvalidCalldata(); + error MustBeSubscriptionOwner(); + error TimeoutNotExceeded(); + error MustBeProposedOwner(address proposedOwner); + event FundsRecovered(address to, uint256 amount); + + // ================================================================ + // | Request state | + // ================================================================ + + mapping(bytes32 requestId => bytes32 commitmentHash) internal s_requestCommitments; + + struct Receipt { + uint96 callbackGasCostJuels; + uint96 totalCostJuels; + } + + event RequestTimedOut(bytes32 indexed requestId); + + // ================================================================ + // | Initialization | + // ================================================================ + constructor(address link) { + i_linkToken = IERC20(link); + } + + // ================================================================ + // | Request/Response | + // ================================================================ + + /// @notice Sets a request as in-flight + /// @dev Only callable within the Router + function _markRequestInFlight(address client, uint64 subscriptionId, uint96 estimatedTotalCostJuels) internal { + // Earmark subscription funds + s_subscriptions[subscriptionId].blockedBalance += estimatedTotalCostJuels; + + // Increment sent requests + s_consumers[client][subscriptionId].initiatedRequests += 1; + } + + /// @notice Moves funds from one subscription account to another. + /// @dev Only callable by the Coordinator contract that is saved in the request commitment + function _pay( + uint64 subscriptionId, + uint96 estimatedTotalCostJuels, + address client, + uint96 adminFee, + uint96 juelsPerGas, + uint96 gasUsed, + uint96 costWithoutCallbackJuels + ) internal returns (Receipt memory) { + uint96 callbackGasCostJuels = juelsPerGas * gasUsed; + uint96 totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels; + + if ( + s_subscriptions[subscriptionId].balance < totalCostJuels || + s_subscriptions[subscriptionId].blockedBalance < estimatedTotalCostJuels + ) { + revert InsufficientBalance(s_subscriptions[subscriptionId].balance); + } + + // Charge the subscription + s_subscriptions[subscriptionId].balance -= totalCostJuels; + + // Unblock earmarked funds + s_subscriptions[subscriptionId].blockedBalance -= estimatedTotalCostJuels; + + // Pay the DON's fees and gas reimbursement + s_withdrawableTokens[msg.sender] += costWithoutCallbackJuels + callbackGasCostJuels; + + // Pay out the administration fee + s_withdrawableTokens[address(this)] += adminFee; + + // Increment finished requests + s_consumers[client][subscriptionId].completedRequests += 1; + + return Receipt({callbackGasCostJuels: callbackGasCostJuels, totalCostJuels: totalCostJuels}); + } + + // ================================================================ + // | Owner methods | + // ================================================================ + + /// @inheritdoc IFunctionsSubscriptions + function ownerCancelSubscription(uint64 subscriptionId) external override { + _onlyRouterOwner(); + _isExistingSubscription(subscriptionId); + _cancelSubscriptionHelper(subscriptionId, s_subscriptions[subscriptionId].owner, false); + } + + /// @inheritdoc IFunctionsSubscriptions + function recoverFunds(address to) external override { + _onlyRouterOwner(); + uint256 externalBalance = i_linkToken.balanceOf(address(this)); + uint256 internalBalance = uint256(s_totalLinkBalance); + if (internalBalance < externalBalance) { + uint256 amount = externalBalance - internalBalance; + i_linkToken.safeTransfer(to, amount); + emit FundsRecovered(to, amount); + } + // If the balances are equal, nothing to be done. + } + + // ================================================================ + // | Fund withdrawal | + // ================================================================ + + /// @inheritdoc IFunctionsSubscriptions + function oracleWithdraw(address recipient, uint96 amount) external override { + _whenNotPaused(); + + if (amount == 0) { + revert InvalidCalldata(); + } + uint96 currentBalance = s_withdrawableTokens[msg.sender]; + if (currentBalance < amount) { + revert InsufficientBalance(currentBalance); + } + s_withdrawableTokens[msg.sender] -= amount; + s_totalLinkBalance -= amount; + i_linkToken.safeTransfer(recipient, amount); + } + + /// @notice Owner withdraw LINK earned through admin fees + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw + function ownerWithdraw(address recipient, uint96 amount) external { + _onlyRouterOwner(); + if (amount == 0) { + amount = s_withdrawableTokens[address(this)]; + } + uint96 currentBalance = s_withdrawableTokens[address(this)]; + if (currentBalance < amount) { + revert InsufficientBalance(currentBalance); + } + s_withdrawableTokens[address(this)] -= amount; + s_totalLinkBalance -= amount; + + i_linkToken.safeTransfer(recipient, amount); + } + + // ================================================================ + // | TransferAndCall Deposit helper | + // ================================================================ + + // This function is to be invoked when using LINK.transferAndCall + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); + function onTokenTransfer(address /* sender */, uint256 amount, bytes calldata data) external override { + _whenNotPaused(); + if (msg.sender != address(i_linkToken)) { + revert OnlyCallableFromLink(); + } + if (data.length != 32) { + revert InvalidCalldata(); + } + uint64 subscriptionId = abi.decode(data, (uint64)); + if (s_subscriptions[subscriptionId].owner == address(0)) { + revert InvalidSubscription(); + } + // We do not check that the msg.sender is the subscription owner, + // anyone can fund a subscription. + uint256 oldBalance = s_subscriptions[subscriptionId].balance; + s_subscriptions[subscriptionId].balance += uint96(amount); + s_totalLinkBalance += uint96(amount); + emit SubscriptionFunded(subscriptionId, oldBalance, oldBalance + amount); + } + + // ================================================================ + // | Subscription management | + // ================================================================ + + /// @inheritdoc IFunctionsSubscriptions + function getTotalBalance() external view override returns (uint96) { + return s_totalLinkBalance; + } + + /// @inheritdoc IFunctionsSubscriptions + function getSubscriptionCount() external view override returns (uint64) { + return s_currentSubscriptionId; + } + + /// @inheritdoc IFunctionsSubscriptions + function getSubscription(uint64 subscriptionId) public view override returns (Subscription memory) { + _isExistingSubscription(subscriptionId); + return s_subscriptions[subscriptionId]; + } + + /// @inheritdoc IFunctionsSubscriptions + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view override returns (Subscription[] memory subscriptions) { + if ( + subscriptionIdStart > subscriptionIdEnd || + subscriptionIdEnd > s_currentSubscriptionId || + s_currentSubscriptionId == 0 + ) { + revert InvalidCalldata(); + } + + subscriptions = new Subscription[]((subscriptionIdEnd - subscriptionIdStart) + 1); + for (uint256 i = 0; i <= subscriptionIdEnd - subscriptionIdStart; ++i) { + subscriptions[i] = s_subscriptions[uint64(subscriptionIdStart + i)]; + } + + return subscriptions; + } + + /// @inheritdoc IFunctionsSubscriptions + function getConsumer(address client, uint64 subscriptionId) public view override returns (Consumer memory) { + return s_consumers[client][subscriptionId]; + } + + /// @dev Used within this file & FunctionsRouter.sol + function _isExistingSubscription(uint64 subscriptionId) internal view { + if (s_subscriptions[subscriptionId].owner == address(0)) { + revert InvalidSubscription(); + } + } + + /// @dev Used within FunctionsRouter.sol + function _isAllowedConsumer(address client, uint64 subscriptionId) internal view { + if (!s_consumers[client][subscriptionId].allowed) { + revert InvalidConsumer(); + } + } + + /// @inheritdoc IFunctionsSubscriptions + function createSubscription() external override returns (uint64 subscriptionId) { + _whenNotPaused(); + _onlySenderThatAcceptedToS(); + + subscriptionId = ++s_currentSubscriptionId; + s_subscriptions[subscriptionId] = Subscription({ + balance: 0, + blockedBalance: 0, + owner: msg.sender, + proposedOwner: address(0), + consumers: new address[](0), + flags: bytes32(0) + }); + + emit SubscriptionCreated(subscriptionId, msg.sender); + + return subscriptionId; + } + + /// @inheritdoc IFunctionsSubscriptions + function createSubscriptionWithConsumer(address consumer) external override returns (uint64 subscriptionId) { + _whenNotPaused(); + _onlySenderThatAcceptedToS(); + + subscriptionId = ++s_currentSubscriptionId; + s_subscriptions[subscriptionId] = Subscription({ + balance: 0, + blockedBalance: 0, + owner: msg.sender, + proposedOwner: address(0), + consumers: new address[](0), + flags: bytes32(0) + }); + + s_subscriptions[subscriptionId].consumers.push(consumer); + s_consumers[consumer][subscriptionId].allowed = true; + + emit SubscriptionCreated(subscriptionId, msg.sender); + emit SubscriptionConsumerAdded(subscriptionId, consumer); + + return subscriptionId; + } + + /// @inheritdoc IFunctionsSubscriptions + function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + if (newOwner == address(0) || s_subscriptions[subscriptionId].proposedOwner == newOwner) { + revert InvalidCalldata(); + } + + s_subscriptions[subscriptionId].proposedOwner = newOwner; + emit SubscriptionOwnerTransferRequested(subscriptionId, msg.sender, newOwner); + } + + /// @inheritdoc IFunctionsSubscriptions + function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external override { + _whenNotPaused(); + _onlySenderThatAcceptedToS(); + + address previousOwner = s_subscriptions[subscriptionId].owner; + address proposedOwner = s_subscriptions[subscriptionId].proposedOwner; + if (proposedOwner != msg.sender) { + revert MustBeProposedOwner(proposedOwner); + } + s_subscriptions[subscriptionId].owner = msg.sender; + s_subscriptions[subscriptionId].proposedOwner = address(0); + emit SubscriptionOwnerTransferred(subscriptionId, previousOwner, msg.sender); + } + + /// @inheritdoc IFunctionsSubscriptions + function removeConsumer(uint64 subscriptionId, address consumer) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + Consumer memory consumerData = s_consumers[consumer][subscriptionId]; + _isAllowedConsumer(consumer, subscriptionId); + if (consumerData.initiatedRequests != consumerData.completedRequests) { + revert CannotRemoveWithPendingRequests(); + } + // Note bounded by config.maxConsumers + address[] memory consumers = s_subscriptions[subscriptionId].consumers; + for (uint256 i = 0; i < consumers.length; ++i) { + if (consumers[i] == consumer) { + // Storage write to preserve last element + s_subscriptions[subscriptionId].consumers[i] = consumers[consumers.length - 1]; + // Storage remove last element + s_subscriptions[subscriptionId].consumers.pop(); + break; + } + } + delete s_consumers[consumer][subscriptionId]; + emit SubscriptionConsumerRemoved(subscriptionId, consumer); + } + + /// @dev Overriden in FunctionsRouter.sol + function _getMaxConsumers() internal view virtual returns (uint16); + + /// @inheritdoc IFunctionsSubscriptions + function addConsumer(uint64 subscriptionId, address consumer) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + // Already maxed, cannot add any more consumers. + uint16 maximumConsumers = _getMaxConsumers(); + if (s_subscriptions[subscriptionId].consumers.length >= maximumConsumers) { + revert TooManyConsumers(maximumConsumers); + } + if (s_consumers[consumer][subscriptionId].allowed) { + // Idempotence - do nothing if already added. + // Ensures uniqueness in s_subscriptions[subscriptionId].consumers. + return; + } + + s_consumers[consumer][subscriptionId].allowed = true; + s_subscriptions[subscriptionId].consumers.push(consumer); + + emit SubscriptionConsumerAdded(subscriptionId, consumer); + } + + /// @dev Overriden in FunctionsRouter.sol + function _getSubscriptionDepositDetails() internal virtual returns (uint16, uint72); + + function _cancelSubscriptionHelper(uint64 subscriptionId, address toAddress, bool checkDepositRefundability) private { + Subscription memory subscription = s_subscriptions[subscriptionId]; + uint96 balance = subscription.balance; + uint64 completedRequests = 0; + + // NOTE: loop iterations are bounded by config.maxConsumers + // If no consumers, does nothing. + for (uint256 i = 0; i < subscription.consumers.length; ++i) { + address consumer = subscription.consumers[i]; + completedRequests += s_consumers[consumer][subscriptionId].completedRequests; + delete s_consumers[consumer][subscriptionId]; + } + delete s_subscriptions[subscriptionId]; + + (uint16 subscriptionDepositMinimumRequests, uint72 subscriptionDepositJuels) = _getSubscriptionDepositDetails(); + + // If subscription has not made enough requests, deposit will be forfeited + if (checkDepositRefundability && completedRequests < subscriptionDepositMinimumRequests) { + uint96 deposit = subscriptionDepositJuels > balance ? balance : subscriptionDepositJuels; + if (deposit > 0) { + s_withdrawableTokens[address(this)] += deposit; + balance -= deposit; + } + } + + if (balance > 0) { + s_totalLinkBalance -= balance; + i_linkToken.safeTransfer(toAddress, uint256(balance)); + } + emit SubscriptionCanceled(subscriptionId, toAddress, balance); + } + + /// @inheritdoc IFunctionsSubscriptions + function cancelSubscription(uint64 subscriptionId, address to) external override { + _whenNotPaused(); + _onlySubscriptionOwner(subscriptionId); + _onlySenderThatAcceptedToS(); + + if (pendingRequestExists(subscriptionId)) { + revert CannotRemoveWithPendingRequests(); + } + + _cancelSubscriptionHelper(subscriptionId, to, true); + } + + /// @inheritdoc IFunctionsSubscriptions + function pendingRequestExists(uint64 subscriptionId) public view override returns (bool) { + address[] memory consumers = s_subscriptions[subscriptionId].consumers; + // NOTE: loop iterations are bounded by config.maxConsumers + for (uint256 i = 0; i < consumers.length; ++i) { + Consumer memory consumer = s_consumers[consumers[i]][subscriptionId]; + if (consumer.initiatedRequests != consumer.completedRequests) { + return true; + } + } + return false; + } + + /// @inheritdoc IFunctionsSubscriptions + function setFlags(uint64 subscriptionId, bytes32 flags) external override { + _onlyRouterOwner(); + _isExistingSubscription(subscriptionId); + s_subscriptions[subscriptionId].flags = flags; + } + + /// @inheritdoc IFunctionsSubscriptions + function getFlags(uint64 subscriptionId) public view returns (bytes32) { + return s_subscriptions[subscriptionId].flags; + } + + // ================================================================ + // | Request Timeout | + // ================================================================ + + /// @inheritdoc IFunctionsSubscriptions + function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external override { + _whenNotPaused(); + + for (uint256 i = 0; i < requestsToTimeoutByCommitment.length; ++i) { + FunctionsResponse.Commitment memory request = requestsToTimeoutByCommitment[i]; + bytes32 requestId = request.requestId; + uint64 subscriptionId = request.subscriptionId; + + // Check that request ID is valid + if (keccak256(abi.encode(request)) != s_requestCommitments[requestId]) { + revert InvalidCalldata(); + } + + // Check that request has exceeded allowed request time + if (block.timestamp < request.timeoutTimestamp) { + revert TimeoutNotExceeded(); + } + + // Notify the Coordinator that the request should no longer be fulfilled + IFunctionsBilling(request.coordinator).deleteCommitment(requestId); + // Release the subscription's balance that had been earmarked for the request + s_subscriptions[subscriptionId].blockedBalance -= request.estimatedTotalCostJuels; + s_consumers[request.client][subscriptionId].completedRequests += 1; + // Delete commitment within Router state + delete s_requestCommitments[requestId]; + + emit RequestTimedOut(requestId); + } + } + + // ================================================================ + // | Modifiers | + // ================================================================ + + function _onlySubscriptionOwner(uint64 subscriptionId) internal view { + address owner = s_subscriptions[subscriptionId].owner; + if (owner == address(0)) { + revert InvalidSubscription(); + } + if (msg.sender != owner) { + revert MustBeSubscriptionOwner(); + } + } + + /// @dev Overriden in FunctionsRouter.sol + function _onlySenderThatAcceptedToS() internal virtual; + + /// @dev Overriden in FunctionsRouter.sol + function _onlyRouterOwner() internal virtual; + + /// @dev Overriden in FunctionsRouter.sol + function _whenNotPaused() internal virtual; +} diff --git a/contracts/src/v0.8/functions/v1_0_0/Routable.sol b/contracts/src/v0.8/functions/v1_0_0/Routable.sol new file mode 100644 index 00000000000..6c11d4d6180 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/Routable.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IOwnableFunctionsRouter} from "./interfaces/IOwnableFunctionsRouter.sol"; + +/// @title This abstract should be inherited by contracts that will be used +/// as the destinations to a route (id=>contract) on the Router. +/// It provides a Router getter and modifiers. +abstract contract Routable is ITypeAndVersion { + IOwnableFunctionsRouter private immutable i_router; + + error RouterMustBeSet(); + error OnlyCallableByRouter(); + error OnlyCallableByRouterOwner(); + + /// @dev Initializes the contract. + constructor(address router) { + if (router == address(0)) { + revert RouterMustBeSet(); + } + i_router = IOwnableFunctionsRouter(router); + } + + /// @notice Return the Router + function _getRouter() internal view returns (IOwnableFunctionsRouter router) { + return i_router; + } + + /// @notice Reverts if called by anyone other than the router. + modifier onlyRouter() { + if (msg.sender != address(i_router)) { + revert OnlyCallableByRouter(); + } + _; + } + + /// @notice Reverts if called by anyone other than the router owner. + modifier onlyRouterOwner() { + if (msg.sender != i_router.owner()) { + revert OnlyCallableByRouterOwner(); + } + _; + } +} diff --git a/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol new file mode 100644 index 00000000000..a7b13577842 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/accessControl/TermsOfServiceAllowList.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITermsOfServiceAllowList} from "./interfaces/ITermsOfServiceAllowList.sol"; +import {IAccessController} from "../../../shared/interfaces/IAccessController.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; + +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; + +import {Address} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/structs/EnumerableSet.sol"; + +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, ITypeAndVersion, ConfirmedOwner { + using Address for address; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @inheritdoc ITypeAndVersion + string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; + + EnumerableSet.AddressSet private s_allowedSenders; + mapping(address => bool) private s_blockedSenders; + + event AddedAccess(address user); + event BlockedAccess(address user); + event UnblockedAccess(address user); + + error InvalidSignature(); + error InvalidUsage(); + error RecipientIsBlocked(); + + // ================================================================ + // | Configuration state | + // ================================================================ + struct Config { + bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. + address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data + } + + Config private s_config; + + event ConfigUpdated(Config config); + + // ================================================================ + // | Initialization | + // ================================================================ + + constructor(Config memory config) ConfirmedOwner(msg.sender) { + updateConfig(config); + } + + // ================================================================ + // | Configuration | + // ================================================================ + + /// @notice Gets the contracts's configuration + /// @return config + function getConfig() external view returns (Config memory) { + return s_config; + } + + /// @notice Sets the contracts's configuration + /// @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information + function updateConfig(Config memory config) public onlyOwner { + s_config = config; + emit ConfigUpdated(config); + } + + // ================================================================ + // | Allow methods | + // ================================================================ + + /// @inheritdoc ITermsOfServiceAllowList + function getMessage(address acceptor, address recipient) public pure override returns (bytes32) { + return keccak256(abi.encodePacked(acceptor, recipient)); + } + + /// @inheritdoc ITermsOfServiceAllowList + function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { + if (s_blockedSenders[recipient]) { + revert RecipientIsBlocked(); + } + + // Validate that the signature is correct and the correct data has been signed + bytes32 prefixedMessage = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", getMessage(acceptor, recipient)) + ); + if (ecrecover(prefixedMessage, v, r, s) != s_config.signerPublicKey) { + revert InvalidSignature(); + } + + // If contract, validate that msg.sender == recipient + // This is to prevent EoAs from claiming contracts that they are not in control of + // If EoA, validate that msg.sender == acceptor == recipient + // This is to prevent EoAs from accepting for other EoAs + if (msg.sender != recipient || (msg.sender != acceptor && !msg.sender.isContract())) { + revert InvalidUsage(); + } + + // Add recipient to the allow list + s_allowedSenders.add(recipient); + emit AddedAccess(recipient); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllAllowedSenders() external view override returns (address[] memory) { + return s_allowedSenders.values(); + } + + /// @inheritdoc IAccessController + function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { + if (!s_config.enabled) { + return true; + } + return s_allowedSenders.contains(user); + } + + // ================================================================ + // | Block methods | + // ================================================================ + + /// @inheritdoc ITermsOfServiceAllowList + function isBlockedSender(address sender) external view override returns (bool) { + if (!s_config.enabled) { + return false; + } + return s_blockedSenders[sender]; + } + + /// @inheritdoc ITermsOfServiceAllowList + function blockSender(address sender) external override onlyOwner { + s_allowedSenders.remove(sender); + s_blockedSenders[sender] = true; + emit BlockedAccess(sender); + } + + /// @inheritdoc ITermsOfServiceAllowList + function unblockSender(address sender) external override onlyOwner { + s_blockedSenders[sender] = false; + emit UnblockedAccess(sender); + } +} diff --git a/contracts/src/v0.8/functions/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol new file mode 100644 index 00000000000..af4daa18bc3 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @notice A contract to handle access control of subscription management dependent on signing a Terms of Service +interface ITermsOfServiceAllowList { + /// @notice Return the message data for the proof given to accept the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @return Hash of the message data + function getMessage(address acceptor, address recipient) external pure returns (bytes32); + + /// @notice Check if the address is blocked for usage + /// @param sender The transaction sender's address + /// @return True or false + function isBlockedSender(address sender) external returns (bool); + + /// @notice Get a list of all allowed senders + /// @dev WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + /// to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + /// this function has an unbounded cost, and using it as part of a state-changing function may render the function + /// uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + /// @return addresses - all allowed addresses + function getAllAllowedSenders() external view returns (address[] memory); + + /// @notice Allows access to the sender based on acceptance of the Terms of Service + /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI + /// @param recipient - The recipient address that the acceptor is taking responsibility for + /// @param r - ECDSA signature r data produced by the Chainlink Functions Subscription UI + /// @param s - ECDSA signature s produced by the Chainlink Functions Subscription UI + /// @param v - ECDSA signature v produced by the Chainlink Functions Subscription UI + function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external; + + /// @notice Removes a sender's access if already authorized, and disallows re-accepting the Terms of Service + /// @param sender - Address of the sender to block + function blockSender(address sender) external; + + /// @notice Re-allows a previously blocked sender to accept the Terms of Service + /// @param sender - Address of the sender to unblock + function unblockSender(address sender) external; +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/example/FunctionsClientExample.sol b/contracts/src/v0.8/functions/v1_0_0/example/FunctionsClientExample.sol similarity index 97% rename from contracts/src/v0.8/functions/dev/v1_0_0/example/FunctionsClientExample.sol rename to contracts/src/v0.8/functions/v1_0_0/example/FunctionsClientExample.sol index f0f154c07b2..8d1cf36c6c4 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/example/FunctionsClientExample.sol +++ b/contracts/src/v0.8/functions/v1_0_0/example/FunctionsClientExample.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; import {FunctionsClient} from "../FunctionsClient.sol"; -import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {FunctionsRequest} from "../libraries/FunctionsRequest.sol"; /// @title Chainlink Functions example Client contract implementation diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsBilling.sol new file mode 100644 index 00000000000..6291d05e57c --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsBilling.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @title Chainlink Functions DON billing interface. +interface IFunctionsBilling { + /// @notice Return the current conversion from WEI of ETH to LINK from the configured Chainlink data feed + /// @return weiPerUnitLink - The amount of WEI in one LINK + function getWeiPerUnitLink() external view returns (uint256); + + /// @notice Determine the fee that will be split between Node Operators for servicing a request + /// @param requestCBOR - CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request + /// @return fee - Cost in Juels (1e18) of LINK + function getDONFee(bytes memory requestCBOR) external view returns (uint72); + + /// @notice Determine the fee that will be paid to the Router owner for operating the network + /// @return fee - Cost in Juels (1e18) of LINK + function getAdminFee() external view returns (uint72); + + /// @notice Estimate the total cost that will be charged to a subscription to make a request: transmitter gas re-reimbursement, plus DON fee, plus Registry fee + /// @param - subscriptionId An identifier of the billing account + /// @param - data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param - callbackGasLimit Gas limit for the fulfillment callback + /// @param - gasPriceWei The blockchain's gas price to estimate with + /// @return - billedCost Cost in Juels (1e18) of LINK + function estimateCost( + uint64 subscriptionId, + bytes calldata data, + uint32 callbackGasLimit, + uint256 gasPriceWei + ) external view returns (uint96); + + /// @notice Remove a request commitment that the Router has determined to be stale + /// @param requestId - The request ID to remove + function deleteCommitment(bytes32 requestId) external; + + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @param recipient where to send the funds + /// @param amount amount to withdraw + function oracleWithdraw(address recipient, uint96 amount) external; + + /// @notice Withdraw all LINK earned by Oracles through fulfilling requests + function oracleWithdrawAll() external; +} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsClient.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsClient.sol new file mode 100644 index 00000000000..f28a41666b5 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsClient.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @title Chainlink Functions client interface. +interface IFunctionsClient { + /// @notice Chainlink Functions response handler called by the Functions Router + /// during fullilment from the designated transmitter node in an OCR round. + /// @param requestId The requestId returned by FunctionsClient.sendRequest(). + /// @param response Aggregated response from the request's source code. + /// @param err Aggregated error either from the request's source code or from the execution pipeline. + /// @dev Either response or error parameter will be set, but never both. + function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external; +} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsCoordinator.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsCoordinator.sol new file mode 100644 index 00000000000..4e2bd703dc4 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsCoordinator.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; + +/// @title Chainlink Functions DON Coordinator interface. +interface IFunctionsCoordinator { + /// @notice Returns the DON's threshold encryption public key used to encrypt secrets + /// @dev All nodes on the DON have separate key shares of the threshold decryption key + /// and nodes must participate in a threshold decryption OCR round to decrypt secrets + /// @return thresholdPublicKey the DON's threshold encryption public key + function getThresholdPublicKey() external view returns (bytes memory); + + /// @notice Sets the DON's threshold encryption public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param thresholdPublicKey The new public key + function setThresholdPublicKey(bytes calldata thresholdPublicKey) external; + + /// @notice Returns the DON's secp256k1 public key that is used to encrypt secrets + /// @dev All nodes on the DON have the corresponding private key + /// needed to decrypt the secrets encrypted with the public key + /// @return publicKey the DON's public key + function getDONPublicKey() external view returns (bytes memory); + + /// @notice Sets DON's secp256k1 public key used to encrypt secrets + /// @dev Used to rotate the key + /// @param donPublicKey The new public key + function setDONPublicKey(bytes calldata donPublicKey) external; + + /// @notice Receives a request to be emitted to the DON for processing + /// @param request The request metadata + /// @dev see the struct for field descriptions + /// @return commitment - The parameters of the request that must be held consistent at response time + function startRequest( + FunctionsResponse.RequestMeta calldata request + ) external returns (FunctionsResponse.Commitment memory commitment); +} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsRouter.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsRouter.sol new file mode 100644 index 00000000000..5f93aac873e --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsRouter.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; + +/// @title Chainlink Functions Router interface. +interface IFunctionsRouter { + /// @notice The identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions + /// @return id - bytes32 id that can be passed to the "getContractById" of the Router + function getAllowListId() external view returns (bytes32); + + /// @notice Set the identifier of the route to retrieve the address of the access control contract + /// The access control contract controls which accounts can manage subscriptions + function setAllowListId(bytes32 allowListId) external; + + /// @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network + /// @return adminFee + function getAdminFee() external view returns (uint72 adminFee); + + /// @notice Sends a request using the provided subscriptionId + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier + function sendRequest( + uint64 subscriptionId, + bytes calldata data, + uint16 dataVersion, + uint32 callbackGasLimit, + bytes32 donId + ) external returns (bytes32); + + /// @notice Sends a request to the proposed contracts + /// @param subscriptionId - A unique subscription ID allocated by billing system, + /// a client can make requests from different contracts referencing the same subscription + /// @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request + /// @param dataVersion - Gas limit for the fulfillment callback + /// @param callbackGasLimit - Gas limit for the fulfillment callback + /// @param donId - An identifier used to determine which route to send the request along + /// @return requestId - A unique request identifier + function sendRequestToProposed( + uint64 subscriptionId, + bytes calldata data, + uint16 dataVersion, + uint32 callbackGasLimit, + bytes32 donId + ) external returns (bytes32); + + /// @notice Fulfill the request by: + /// - calling back the data that the Oracle returned to the client contract + /// - pay the DON for processing the request + /// @dev Only callable by the Coordinator contract that is saved in the commitment + /// @param response response data from DON consensus + /// @param err error from DON consensus + /// @param juelsPerGas - current rate of juels/gas + /// @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment + /// @param transmitter - The Node that transmitted the OCR report + /// @param commitment - The parameters of the request that must be held consistent between request and response time + /// @return fulfillResult - + /// @return callbackGasCostJuels - + function fulfill( + bytes memory response, + bytes memory err, + uint96 juelsPerGas, + uint96 costWithoutFulfillment, + address transmitter, + FunctionsResponse.Commitment memory commitment + ) external returns (FunctionsResponse.FulfillResult, uint96); + + /// @notice Validate requested gas limit is below the subscription max. + /// @param subscriptionId subscription ID + /// @param callbackGasLimit desired callback gas limit + function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view; + + /// @notice Get the current contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current contract address + function getContractById(bytes32 id) external view returns (address); + + /// @notice Get the proposed next contract given an ID + /// @param id A bytes32 identifier for the route + /// @return contract The current or proposed contract address + function getProposedContractById(bytes32 id) external view returns (address); + + /// @notice Return the latest proprosal set + /// @return ids The identifiers of the contracts to update + /// @return to The addresses of the contracts that will be updated to + function getProposedContractSet() external view returns (bytes32[] memory, address[] memory); + + /// @notice Proposes one or more updates to the contract routes + /// @dev Only callable by owner + function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external; + + /// @notice Updates the current contract routes to the proposed contracts + /// @dev Only callable by owner + function updateContracts() external; + + /// @dev Puts the system into an emergency stopped state. + /// @dev Only callable by owner + function pause() external; + + /// @dev Takes the system out of an emergency stopped state. + /// @dev Only callable by owner + function unpause() external; +} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsSubscriptions.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsSubscriptions.sol new file mode 100644 index 00000000000..eafd6f4fe99 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IFunctionsSubscriptions.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {FunctionsResponse} from "../libraries/FunctionsResponse.sol"; + +/// @title Chainlink Functions Subscription interface. +interface IFunctionsSubscriptions { + struct Subscription { + uint96 balance; // ═════════╗ Common LINK balance that is controlled by the Router to be used for all consumer requests. + address owner; // ══════════╝ The owner can fund/withdraw/cancel the subscription. + uint96 blockedBalance; // ══╗ LINK balance that is reserved to pay for pending consumer requests. + address proposedOwner; // ══╝ For safely transferring sub ownership. + address[] consumers; // ════╸ Client contracts that can use the subscription + bytes32 flags; // ══════════╸ Per-subscription flags + } + + struct Consumer { + bool allowed; // ══════════════╗ Owner can fund/withdraw/cancel the sub. + uint64 initiatedRequests; // ║ The number of requests that have been started + uint64 completedRequests; // ══╝ The number of requests that have successfully completed or timed out + } + + /// @notice Get details about a subscription. + /// @param subscriptionId - the ID of the subscription + /// @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure + function getSubscription(uint64 subscriptionId) external view returns (Subscription memory); + + /// @notice Retrieve details about multiple subscriptions using an inclusive range + /// @param subscriptionIdStart - the ID of the subscription to start the range at + /// @param subscriptionIdEnd - the ID of the subscription to end the range at + /// @return subscriptions - see IFunctionsSubscriptions.Subscription for more information on the structure + function getSubscriptionsInRange( + uint64 subscriptionIdStart, + uint64 subscriptionIdEnd + ) external view returns (Subscription[] memory); + + /// @notice Get details about a consumer of a subscription. + /// @param client - the consumer contract address + /// @param subscriptionId - the ID of the subscription + /// @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure + function getConsumer(address client, uint64 subscriptionId) external view returns (Consumer memory); + + /// @notice Get details about the total amount of LINK within the system + /// @return totalBalance - total Juels of LINK held by the contract + function getTotalBalance() external view returns (uint96); + + /// @notice Get details about the total number of subscription accounts + /// @return count - total number of subscriptions in the system + function getSubscriptionCount() external view returns (uint64); + + /// @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled + /// @param requestsToTimeoutByCommitment - A list of request commitments to time out + /// @dev The commitment can be found on the "OracleRequest" event created when sending the request. + function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external; + + /// @notice Oracle withdraw LINK earned through fulfilling requests + /// @notice If amount is 0 the full balance will be withdrawn + /// @notice Both signing and transmitting wallets will have a balance to withdraw + /// @param recipient where to send the funds + /// @param amount amount to withdraw + function oracleWithdraw(address recipient, uint96 amount) external; + + /// @notice Owner cancel subscription, sends remaining link directly to the subscription owner. + /// @dev Only callable by the Router Owner + /// @param subscriptionId subscription id + /// @dev notably can be called even if there are pending requests, outstanding ones may fail onchain + function ownerCancelSubscription(uint64 subscriptionId) external; + + /// @notice Recover link sent with transfer instead of transferAndCall. + /// @dev Only callable by the Router Owner + /// @param to address to send link to + function recoverFunds(address to) external; + + /// @notice Create a new subscription. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); + function createSubscription() external returns (uint64); + + /// @notice Create a new subscription and add a consumer. + /// @return subscriptionId - A unique subscription id. + /// @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + /// @dev Note to fund the subscription, use transferAndCall. For example + /// @dev LINKTOKEN.transferAndCall( + /// @dev address(ROUTER), + /// @dev amount, + /// @dev abi.encode(subscriptionId)); + function createSubscriptionWithConsumer(address consumer) external returns (uint64 subscriptionId); + + /// @notice Propose a new owner for a subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param newOwner - proposed new owner of the subscription + function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external; + + /// @notice Accept an ownership transfer. + /// @param subscriptionId - ID of the subscription + /// @dev will revert if original owner of subscriptionId has not requested that msg.sender become the new owner. + function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external; + + /// @notice Remove a consumer from a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - Consumer to remove from the subscription + function removeConsumer(uint64 subscriptionId, address consumer) external; + + /// @notice Add a consumer to a Chainlink Functions subscription. + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param consumer - New consumer which can use the subscription + function addConsumer(uint64 subscriptionId, address consumer) external; + + /// @notice Cancel a subscription + /// @dev Only callable by the Subscription's owner + /// @param subscriptionId - ID of the subscription + /// @param to - Where to send the remaining LINK to + function cancelSubscription(uint64 subscriptionId, address to) external; + + /// @notice Check to see if there exists a request commitment for all consumers for a given sub. + /// @param subscriptionId - ID of the subscription + /// @return true if there exists at least one unfulfilled request for the subscription, false otherwise. + /// @dev Looping is bounded to MAX_CONSUMERS*(number of DONs). + /// @dev Used to disable subscription canceling while outstanding request are present. + function pendingRequestExists(uint64 subscriptionId) external view returns (bool); + + /// @notice Set subscription specific flags for a subscription. + /// Each byte of the flag is used to represent a resource tier that the subscription can utilize. + /// @param subscriptionId - ID of the subscription + /// @param flags - desired flag values + function setFlags(uint64 subscriptionId, bytes32 flags) external; + + /// @notice Get flags for a given subscription. + /// @param subscriptionId - ID of the subscription + /// @return flags - current flag values + function getFlags(uint64 subscriptionId) external view returns (bytes32); +} diff --git a/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol b/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol new file mode 100644 index 00000000000..89eb48022be --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/interfaces/IOwnableFunctionsRouter.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IFunctionsRouter} from "./IFunctionsRouter.sol"; +import {IOwnable} from "../../../shared/interfaces/IOwnable.sol"; + +/// @title Chainlink Functions Router interface with Ownability. +interface IOwnableFunctionsRouter is IOwnable, IFunctionsRouter { + +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol b/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol similarity index 98% rename from contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol rename to contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol index efc3a811e6a..ef697b5e809 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol +++ b/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsRequest.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; +import {CBOR} from "../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; /// @title Library for encoding the input data of a Functions request into CBOR library FunctionsRequest { diff --git a/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsResponse.sol b/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsResponse.sol new file mode 100644 index 00000000000..65fad665d69 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/libraries/FunctionsResponse.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @title Library of types that are used for fulfillment of a Functions request +library FunctionsResponse { + // Used to send request information from the Router to the Coordinator + struct RequestMeta { + bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request + bytes32 flags; // ═══════════════╸ Per-subscription flags + address requestingContract; // ══╗ The client contract that is sending the request + uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests. + uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network + uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request + uint64 initiatedRequests; // ║ The number of requests that have been started + uint32 callbackGasLimit; // ║ The amount of gas that the callback to the consuming contract will be given + uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data + uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out + address subscriptionOwner; // ═══╝ The owner of the billing subscription + } + + enum FulfillResult { + FULFILLED, // 0 + USER_CALLBACK_ERROR, // 1 + INVALID_REQUEST_ID, // 2 + COST_EXCEEDS_COMMITMENT, // 3 + INSUFFICIENT_GAS_PROVIDED, // 4 + SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5 + INVALID_COMMITMENT // 6 + } + + struct Commitment { + bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request + address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request + uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request + address client; // ════════════════════╗ The client contract that sent the request + uint64 subscriptionId; // ║ Identifier of the billing subscription that will be charged for the request + uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given + uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network + uint72 donFee; // ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request + uint40 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. + uint40 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. + uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out + } +} diff --git a/contracts/src/v0.8/functions/v1_0_0/mocks/FunctionsV1EventsMock.sol b/contracts/src/v0.8/functions/v1_0_0/mocks/FunctionsV1EventsMock.sol new file mode 100644 index 00000000000..68b51f89019 --- /dev/null +++ b/contracts/src/v0.8/functions/v1_0_0/mocks/FunctionsV1EventsMock.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +contract FunctionsV1EventsMock { + struct Config { + uint16 maxConsumersPerSubscription; + uint72 adminFee; + bytes4 handleOracleFulfillmentSelector; + uint16 gasForCallExactCheck; + uint32[] maxCallbackGasLimits; + } + event ConfigUpdated(Config param1); + event ContractProposed( + bytes32 proposedContractSetId, + address proposedContractSetFromAddress, + address proposedContractSetToAddress + ); + event ContractUpdated(bytes32 id, address from, address to); + event FundsRecovered(address to, uint256 amount); + event OwnershipTransferRequested(address indexed from, address indexed to); + event OwnershipTransferred(address indexed from, address indexed to); + event Paused(address account); + event RequestNotProcessed(bytes32 indexed requestId, address coordinator, address transmitter, uint8 resultCode); + event RequestProcessed( + bytes32 indexed requestId, + uint64 indexed subscriptionId, + uint96 totalCostJuels, + address transmitter, + uint8 resultCode, + bytes response, + bytes err, + bytes callbackReturnData + ); + event RequestStart( + bytes32 indexed requestId, + bytes32 indexed donId, + uint64 indexed subscriptionId, + address subscriptionOwner, + address requestingContract, + address requestInitiator, + bytes data, + uint16 dataVersion, + uint32 callbackGasLimit, + uint96 estimatedTotalCostJuels + ); + event RequestTimedOut(bytes32 indexed requestId); + event SubscriptionCanceled(uint64 indexed subscriptionId, address fundsRecipient, uint256 fundsAmount); + event SubscriptionConsumerAdded(uint64 indexed subscriptionId, address consumer); + event SubscriptionConsumerRemoved(uint64 indexed subscriptionId, address consumer); + event SubscriptionCreated(uint64 indexed subscriptionId, address owner); + event SubscriptionFunded(uint64 indexed subscriptionId, uint256 oldBalance, uint256 newBalance); + event SubscriptionOwnerTransferRequested(uint64 indexed subscriptionId, address from, address to); + event SubscriptionOwnerTransferred(uint64 indexed subscriptionId, address from, address to); + event Unpaused(address account); + + function emitConfigUpdated(Config memory param1) public { + emit ConfigUpdated(param1); + } + + function emitContractProposed( + bytes32 proposedContractSetId, + address proposedContractSetFromAddress, + address proposedContractSetToAddress + ) public { + emit ContractProposed(proposedContractSetId, proposedContractSetFromAddress, proposedContractSetToAddress); + } + + function emitContractUpdated(bytes32 id, address from, address to) public { + emit ContractUpdated(id, from, to); + } + + function emitFundsRecovered(address to, uint256 amount) public { + emit FundsRecovered(to, amount); + } + + function emitOwnershipTransferRequested(address from, address to) public { + emit OwnershipTransferRequested(from, to); + } + + function emitOwnershipTransferred(address from, address to) public { + emit OwnershipTransferred(from, to); + } + + function emitPaused(address account) public { + emit Paused(account); + } + + function emitRequestNotProcessed( + bytes32 requestId, + address coordinator, + address transmitter, + uint8 resultCode + ) public { + emit RequestNotProcessed(requestId, coordinator, transmitter, resultCode); + } + + function emitRequestProcessed( + bytes32 requestId, + uint64 subscriptionId, + uint96 totalCostJuels, + address transmitter, + uint8 resultCode, + bytes memory response, + bytes memory err, + bytes memory callbackReturnData + ) public { + emit RequestProcessed( + requestId, + subscriptionId, + totalCostJuels, + transmitter, + resultCode, + response, + err, + callbackReturnData + ); + } + + function emitRequestStart( + bytes32 requestId, + bytes32 donId, + uint64 subscriptionId, + address subscriptionOwner, + address requestingContract, + address requestInitiator, + bytes memory data, + uint16 dataVersion, + uint32 callbackGasLimit, + uint96 estimatedTotalCostJuels + ) public { + emit RequestStart( + requestId, + donId, + subscriptionId, + subscriptionOwner, + requestingContract, + requestInitiator, + data, + dataVersion, + callbackGasLimit, + estimatedTotalCostJuels + ); + } + + function emitRequestTimedOut(bytes32 requestId) public { + emit RequestTimedOut(requestId); + } + + function emitSubscriptionCanceled(uint64 subscriptionId, address fundsRecipient, uint256 fundsAmount) public { + emit SubscriptionCanceled(subscriptionId, fundsRecipient, fundsAmount); + } + + function emitSubscriptionConsumerAdded(uint64 subscriptionId, address consumer) public { + emit SubscriptionConsumerAdded(subscriptionId, consumer); + } + + function emitSubscriptionConsumerRemoved(uint64 subscriptionId, address consumer) public { + emit SubscriptionConsumerRemoved(subscriptionId, consumer); + } + + function emitSubscriptionCreated(uint64 subscriptionId, address owner) public { + emit SubscriptionCreated(subscriptionId, owner); + } + + function emitSubscriptionFunded(uint64 subscriptionId, uint256 oldBalance, uint256 newBalance) public { + emit SubscriptionFunded(subscriptionId, oldBalance, newBalance); + } + + function emitSubscriptionOwnerTransferRequested(uint64 subscriptionId, address from, address to) public { + emit SubscriptionOwnerTransferRequested(subscriptionId, from, to); + } + + function emitSubscriptionOwnerTransferred(uint64 subscriptionId, address from, address to) public { + emit SubscriptionOwnerTransferred(subscriptionId, from, to); + } + + function emitUnpaused(address account) public { + emit Unpaused(account); + } +} diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Abstract.sol b/contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Abstract.sol similarity index 98% rename from contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Abstract.sol rename to contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Abstract.sol index ea4503a8b7d..09c4a825f44 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Abstract.sol +++ b/contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Abstract.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { // Maximum number of oracles the offchain reporting protocol is designed for diff --git a/contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Base.sol similarity index 95% rename from contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Base.sol rename to contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Base.sol index 013cefe82b9..ba671d4468b 100644 --- a/contracts/src/v0.8/functions/dev/v1_0_0/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/v1_0_0/ocr/OCR2Base.sol @@ -1,18 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {OCR2Abstract} from "./OCR2Abstract.sol"; /** * @notice Onchain verification of reports from the offchain reporting protocol - * @dev THIS CONTRACT HAS NOT GONE THROUGH ANY SECURITY REVIEW. DO NOT USE IN PROD. * @dev For details on its operation, see the offchain reporting protocol design * doc, which refers to this contract as simply the "contract". - * @dev This contract is meant to aid rapid development of new applications based on OCR2. - * However, for actual production contracts, it is expected that most of the logic of this contract - * will be folded directly into the application contract. Inheritance prevents us from doing lots - * of juicy storage layout optimizations, leading to a substantial increase in gas cost. */ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { error ReportInvalid(); diff --git a/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol b/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol index 4cb40c104e1..c023e3d2f90 100644 --- a/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol +++ b/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./AggregatorInterface.sol"; -import "./AggregatorV3Interface.sol"; +import {AggregatorInterface} from "./AggregatorInterface.sol"; +import {AggregatorV3Interface} from "./AggregatorV3Interface.sol"; interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {} diff --git a/contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedReceiverInterface.sol b/contracts/src/v0.8/interfaces/AuthorizedReceiverInterface.sol similarity index 100% rename from contracts/src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/AuthorizedReceiverInterface.sol rename to contracts/src/v0.8/interfaces/AuthorizedReceiverInterface.sol diff --git a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol index 512939b38fe..1d2367d82a8 100644 --- a/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol +++ b/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; pragma abicoder v2; -import "./AggregatorV2V3Interface.sol"; +import {AggregatorV2V3Interface} from "./AggregatorV2V3Interface.sol"; interface FeedRegistryInterface { struct Phase { diff --git a/contracts/src/v0.8/interfaces/OperatorInterface.sol b/contracts/src/v0.8/interfaces/OperatorInterface.sol index 14922649159..4114cce16d3 100644 --- a/contracts/src/v0.8/interfaces/OperatorInterface.sol +++ b/contracts/src/v0.8/interfaces/OperatorInterface.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./OracleInterface.sol"; -import "./ChainlinkRequestInterface.sol"; +import {OracleInterface} from "./OracleInterface.sol"; +import {ChainlinkRequestInterface} from "./ChainlinkRequestInterface.sol"; interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { function operatorRequest( @@ -27,10 +27,4 @@ interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { function ownerTransferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success); function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable; - - function getAuthorizedSenders() external returns (address[] memory); - - function setAuthorizedSenders(address[] calldata senders) external; - - function getForwarder() external returns (address); } diff --git a/contracts/src/v0.8/interfaces/OracleInterface.sol b/contracts/src/v0.8/interfaces/OracleInterface.sol index c3a9c5edfb4..40365822e10 100644 --- a/contracts/src/v0.8/interfaces/OracleInterface.sol +++ b/contracts/src/v0.8/interfaces/OracleInterface.sol @@ -11,8 +11,6 @@ interface OracleInterface { bytes32 data ) external returns (bool); - function isAuthorizedSender(address node) external view returns (bool); - function withdraw(address recipient, uint256 amount) external; function withdrawable() external view returns (uint256); diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol index a4c912b8ef0..1eb6cba932d 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./CrossDomainForwarder.sol"; -import "./interfaces/ForwarderInterface.sol"; -import "./interfaces/DelegateForwarderInterface.sol"; +import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; +import {DelegateForwarderInterface} from "./interfaces/DelegateForwarderInterface.sol"; /** * @title CrossDomainDelegateForwarder - L1 xDomain account representation (with delegatecall support) diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol index 4377c2cc0d7..1f9066c5054 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./CrossDomainOwnable.sol"; -import "./interfaces/ForwarderInterface.sol"; +import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; +import {ForwarderInterface} from "./interfaces/ForwarderInterface.sol"; /** * @title CrossDomainForwarder - L1 xDomain account representation diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol index 966a66372fe..b9a435a7e21 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/access/ConfirmedOwner.sol"; -import "./interfaces/CrossDomainOwnableInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {CrossDomainOwnableInterface} from "./interfaces/CrossDomainOwnableInterface.sol"; /** * @title The CrossDomainOwnable contract @@ -42,6 +42,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice validate, transfer ownership, and emit relevant events */ function _transferL1Ownership(address to) internal { + // solhint-disable-next-line custom-errors require(to != msg.sender, "Cannot transfer to self"); s_l1PendingOwner = to; @@ -64,6 +65,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyL1Owner() virtual { + // solhint-disable-next-line custom-errors require(msg.sender == s_l1Owner, "Only callable by L1 owner"); _; } @@ -72,6 +74,7 @@ contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { * @notice Reverts if called by anyone other than the L1 owner. */ modifier onlyProposedL1Owner() virtual { + // solhint-disable-next-line custom-errors require(msg.sender == s_l1PendingOwner, "Only callable by proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/dev/Flags.sol b/contracts/src/v0.8/l2ep/dev/Flags.sol similarity index 88% rename from contracts/src/v0.8/dev/Flags.sol rename to contracts/src/v0.8/l2ep/dev/Flags.sol index a06a67026f3..b943c06d0c3 100644 --- a/contracts/src/v0.8/dev/Flags.sol +++ b/contracts/src/v0.8/l2ep/dev/Flags.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../shared/access/SimpleReadAccessController.sol"; -import "../shared/interfaces/AccessControllerInterface.sol"; -import "../interfaces/TypeAndVersionInterface.sol"; +import {SimpleReadAccessController} from "../../shared/access/SimpleReadAccessController.sol"; +import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol"; +import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; /* dev dependencies - to be re/moved after audit */ -import "./interfaces/FlagsInterface.sol"; +import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; /** * @title The Flags contract @@ -17,11 +17,12 @@ import "./interfaces/FlagsInterface.sol"; * An expected pattern is to allow addresses to raise flags on themselves, so if you are subscribing to * FlagOn events you should filter for addresses you care about. */ -contract Flags is TypeAndVersionInterface, FlagsInterface, SimpleReadAccessController { +// solhint-disable custom-errors +contract Flags is ITypeAndVersion, FlagsInterface, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; AccessControllerInterface public loweringAccessController; - mapping(address => bool) private flags; + mapping(address => bool) private s_flags; event FlagRaised(address indexed subject); event FlagLowered(address indexed subject); @@ -43,7 +44,7 @@ contract Flags is TypeAndVersionInterface, FlagsInterface, SimpleReadAccessContr * - Flags 1.1.0: upgraded to solc 0.8, added lowering access controller * - Flags 1.0.0: initial release * - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "Flags 1.1.0"; @@ -56,7 +57,7 @@ contract Flags is TypeAndVersionInterface, FlagsInterface, SimpleReadAccessContr * false value indicates that no flag was raised. */ function getFlag(address subject) external view override checkAccess returns (bool) { - return flags[subject]; + return s_flags[subject]; } /** @@ -68,7 +69,7 @@ contract Flags is TypeAndVersionInterface, FlagsInterface, SimpleReadAccessContr function getFlags(address[] calldata subjects) external view override checkAccess returns (bool[] memory) { bool[] memory responses = new bool[](subjects.length); for (uint256 i = 0; i < subjects.length; i++) { - responses[i] = flags[subjects[i]]; + responses[i] = s_flags[subjects[i]]; } return responses; } @@ -161,15 +162,15 @@ contract Flags is TypeAndVersionInterface, FlagsInterface, SimpleReadAccessContr } function _tryToRaiseFlag(address subject) private { - if (!flags[subject]) { - flags[subject] = true; + if (!s_flags[subject]) { + s_flags[subject] = true; emit FlagRaised(subject); } } function _tryToLowerFlag(address subject) private { - if (flags[subject]) { - flags[subject] = false; + if (s_flags[subject]) { + s_flags[subject] = false; emit FlagLowered(subject); } } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol index 4f4a197d809..cdab6d49612 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "../CrossDomainForwarder.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumCrossDomainForwarder - L1 xDomain account representation @@ -51,6 +56,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); _; } @@ -59,6 +65,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == AddressAliasHelper.applyL1ToL2Alias(s_l1PendingOwner), "Must be proposed L1 owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol index 8035d07ad2f..2f1d775e489 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol @@ -1,10 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/DelegateForwarderInterface.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "./ArbitrumCrossDomainForwarder.sol"; +// solhint-disable-next-line no-unused-import +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; + +import {ArbitrumCrossDomainForwarder} from "./ArbitrumCrossDomainForwarder.sol"; + +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Arbitrum @@ -51,6 +56,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros * @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. */ modifier onlyLocalOrCrossDomainOwner() { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger() || msg.sender == owner(), "Sender is not the L2 messenger or owner"); _; } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 3c09fb9acad..6d8d31a8085 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -2,15 +2,13 @@ pragma solidity ^0.8.4; import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import {ForwarderInterface} from "./../interfaces/ForwarderInterface.sol"; import {AggregatorInterface} from "../../../interfaces/AggregatorInterface.sol"; import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; import {AggregatorV2V3Interface} from "../../../interfaces/AggregatorV2V3Interface.sol"; import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {FlagsInterface} from "./../../../dev/interfaces/FlagsInterface.sol"; +import {FlagsInterface} from "../interfaces/FlagsInterface.sol"; import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; -import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; /** * @title ArbitrumSequencerUptimeFeed - L2 sequencer uptime status aggregator @@ -55,11 +53,15 @@ contract ArbitrumSequencerUptimeFeed is address public constant FLAG_L2_SEQ_OFFLINE = address(bytes20(bytes32(uint256(keccak256("chainlink.flags.arbitrum-seq-offline")) - 1))); + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 public constant override version = 1; /// @dev Flags contract to raise/lower flags on, during status transitions + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i FlagsInterface public immutable FLAGS; /// @dev L1 address address private s_l1Sender; @@ -72,7 +74,7 @@ contract ArbitrumSequencerUptimeFeed is * @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract */ constructor(address flagsAddress, address l1SenderAddress) { - setL1Sender(l1SenderAddress); + _setL1Sender(l1SenderAddress); FLAGS = FlagsInterface(flagsAddress); } @@ -82,12 +84,12 @@ contract ArbitrumSequencerUptimeFeed is * @dev Mainly used for AggregatorV2V3Interface functions * @param roundId Round ID to check */ - function isValidRound(uint256 roundId) private view returns (bool) { + function _isValidRound(uint256 roundId) private view returns (bool) { return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; } /// @notice Check that this contract is initialised, otherwise throw - function requireInitialized(uint80 latestRoundId) private pure { + function _requireInitialized(uint80 latestRoundId) private pure { if (latestRoundId == 0) { revert Uninitialized(); } @@ -108,7 +110,7 @@ contract ArbitrumSequencerUptimeFeed is bool currentStatus = FLAGS.getFlag(FLAG_L2_SEQ_OFFLINE); // Initialise roundId == 1 as the first round - recordRound(1, currentStatus, timestamp); + _recordRound(1, currentStatus, timestamp); emit Initialized(); } @@ -135,11 +137,11 @@ contract ArbitrumSequencerUptimeFeed is * @param to new L1 sender that will be allowed to call `updateStatus` on this contract */ function transferL1Sender(address to) external virtual onlyOwner { - setL1Sender(to); + _setL1Sender(to); } /// @notice internal method that stores the L1 sender - function setL1Sender(address to) private { + function _setL1Sender(address to) private { address from = s_l1Sender; if (from != to) { s_l1Sender = to; @@ -161,14 +163,14 @@ contract ArbitrumSequencerUptimeFeed is * * @param status The status flag to convert to an aggregator-compatible answer */ - function getStatusAnswer(bool status) private pure returns (int256) { + function _getStatusAnswer(bool status) private pure returns (int256) { return status ? int256(1) : int256(0); } /** * @notice Raise or lower the flag on the stored Flags contract. */ - function forwardStatusToFlags(bool status) private { + function _forwardStatusToFlags(bool status) private { if (status) { FLAGS.raiseFlag(FLAG_L2_SEQ_OFFLINE); } else { @@ -183,7 +185,7 @@ contract ArbitrumSequencerUptimeFeed is * @param status Sequencer status * @param timestamp Block timestamp of status update */ - function recordRound(uint80 roundId, bool status, uint64 timestamp) private { + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { Round memory nextRound = Round(status, timestamp); FeedState memory feedState = FeedState(roundId, status, timestamp); @@ -191,7 +193,7 @@ contract ArbitrumSequencerUptimeFeed is s_feedState = feedState; emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(getStatusAnswer(status), roundId, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); } /** @@ -203,7 +205,7 @@ contract ArbitrumSequencerUptimeFeed is */ function updateStatus(bool status, uint64 timestamp) external override { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); if (msg.sender != aliasedL1MessageSender()) { revert InvalidSender(); } @@ -216,37 +218,37 @@ contract ArbitrumSequencerUptimeFeed is // Prepare a new round with updated status feedState.latestRoundId += 1; - recordRound(feedState.latestRoundId, status, timestamp); + _recordRound(feedState.latestRoundId, status, timestamp); - forwardStatusToFlags(status); + _forwardStatusToFlags(status); } /// @inheritdoc AggregatorInterface function latestAnswer() external view override checkAccess returns (int256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); - return getStatusAnswer(feedState.latestStatus); + _requireInitialized(feedState.latestRoundId); + return _getStatusAnswer(feedState.latestStatus); } /// @inheritdoc AggregatorInterface function latestTimestamp() external view override checkAccess returns (uint256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); return feedState.latestTimestamp; } /// @inheritdoc AggregatorInterface function latestRound() external view override checkAccess returns (uint256) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); return feedState.latestRoundId; } /// @inheritdoc AggregatorInterface function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - requireInitialized(s_feedState.latestRoundId); - if (isValidRound(roundId)) { - return getStatusAnswer(s_rounds[uint80(roundId)].status); + _requireInitialized(s_feedState.latestRoundId); + if (_isValidRound(roundId)) { + return _getStatusAnswer(s_rounds[uint80(roundId)].status); } return 0; @@ -254,8 +256,8 @@ contract ArbitrumSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - requireInitialized(s_feedState.latestRoundId); - if (isValidRound(roundId)) { + _requireInitialized(s_feedState.latestRoundId); + if (_isValidRound(roundId)) { return s_rounds[uint80(roundId)].timestamp; } @@ -272,11 +274,11 @@ contract ArbitrumSequencerUptimeFeed is checkAccess returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { - requireInitialized(s_feedState.latestRoundId); + _requireInitialized(s_feedState.latestRoundId); - if (isValidRound(_roundId)) { + if (_isValidRound(_roundId)) { Round memory round = s_rounds[_roundId]; - answer = getStatusAnswer(round.status); + answer = _getStatusAnswer(round.status); startedAt = uint256(round.timestamp); } else { answer = 0; @@ -296,10 +298,10 @@ contract ArbitrumSequencerUptimeFeed is returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { FeedState memory feedState = s_feedState; - requireInitialized(feedState.latestRoundId); + _requireInitialized(feedState.latestRoundId); roundId = feedState.latestRoundId; - answer = getStatusAnswer(feedState.latestStatus); + answer = _getStatusAnswer(feedState.latestStatus); startedAt = feedState.latestTimestamp; updatedAt = startedAt; answeredInRound = roundId; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index c882a09254a..3b5fd277e56 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/AggregatorValidatorInterface.sol"; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../shared/interfaces/AccessControllerInterface.sol"; -import "../../../interfaces/AggregatorV3Interface.sol"; -import "../../../shared/access/SimpleWriteAccessController.sol"; +import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ -import "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; -import "../../../dev/interfaces/FlagsInterface.sol"; -import "../interfaces/IArbitrumDelayedInbox.sol"; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; -import "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; +import {IArbitrumDelayedInbox} from "../interfaces/IArbitrumDelayedInbox.sol"; +import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; +import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title ArbitrumValidator - makes xDomain L2 Flags contract call (using L2 xDomain Forwarder contract) @@ -36,14 +34,17 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf } /// @dev Precompiled contract that exists in every Arbitrum chain at address(100). Exposes a variety of system-level functionality. - address constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); + address internal constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); int256 private constant ANSWER_SEQ_OFFLINE = 1; /// @notice The address of Arbitrum's DelayedInbox + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable CROSS_DOMAIN_MESSENGER; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_SEQ_STATUS_RECORDER; // L2 xDomain alias address of this contract + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_ALIAS = AddressAliasHelper.applyL1ToL2Alias(address(this)); PaymentStrategy private s_paymentStrategy; @@ -85,7 +86,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf * @param maxGas gas limit for immediate L2 execution attempt. A value around 1M should be sufficient * @param gasPriceBid maximum L2 gas price to pay * @param gasPriceL1FeedAddr address of the L1 gas price feed (used to approximate Arbitrum retryable ticket submission cost) - * @param paymentStrategy strategy describing how the contract pays for xDomain calls + * @param _paymentStrategy strategy describing how the contract pays for xDomain calls */ constructor( address crossDomainMessengerAddr, @@ -95,16 +96,18 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf uint256 gasPriceBid, uint256 baseFee, address gasPriceL1FeedAddr, - PaymentStrategy paymentStrategy + PaymentStrategy _paymentStrategy ) { + // solhint-disable-next-line custom-errors require(crossDomainMessengerAddr != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors require(l2ArbitrumSequencerUptimeFeedAddr != address(0), "Invalid ArbitrumSequencerUptimeFeed contract address"); CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; L2_SEQ_STATUS_RECORDER = l2ArbitrumSequencerUptimeFeedAddr; // Additional L2 payment configuration _setConfigAC(configACAddr); _setGasConfig(maxGas, gasPriceBid, baseFee, gasPriceL1FeedAddr); - _setPaymentStrategy(paymentStrategy); + _setPaymentStrategy(_paymentStrategy); } /** @@ -231,10 +234,10 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /** * @notice sets the payment strategy * @dev access control provided by `configAC` - * @param paymentStrategy strategy describing how the contract pays for xDomain calls + * @param _paymentStrategy strategy describing how the contract pays for xDomain calls */ - function setPaymentStrategy(PaymentStrategy paymentStrategy) external onlyOwnerOrConfigAccess { - _setPaymentStrategy(paymentStrategy); + function setPaymentStrategy(PaymentStrategy _paymentStrategy) external onlyOwnerOrConfigAccess { + _setPaymentStrategy(_paymentStrategy); } /** @@ -289,15 +292,18 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf } /// @notice internal method that stores the payment strategy - function _setPaymentStrategy(PaymentStrategy paymentStrategy) internal { - s_paymentStrategy = paymentStrategy; - emit PaymentStrategySet(paymentStrategy); + function _setPaymentStrategy(PaymentStrategy _paymentStrategy) internal { + s_paymentStrategy = _paymentStrategy; + emit PaymentStrategySet(_paymentStrategy); } /// @notice internal method that stores the gas configuration function _setGasConfig(uint256 maxGas, uint256 gasPriceBid, uint256 baseFee, address gasPriceL1FeedAddr) internal { + // solhint-disable-next-line custom-errors require(maxGas > 0, "Max gas is zero"); + // solhint-disable-next-line custom-errors require(gasPriceBid > 0, "Gas price bid is zero"); + // solhint-disable-next-line custom-errors require(gasPriceL1FeedAddr != address(0), "Gas price Aggregator is zero address"); s_gasConfig = GasConfig(maxGas, gasPriceBid, baseFee, gasPriceL1FeedAddr); emit GasConfigSet(maxGas, gasPriceBid, gasPriceL1FeedAddr); @@ -337,6 +343,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf /// @dev reverts if the caller does not have access to change the configuration modifier onlyOwnerOrConfigAccess() { + // solhint-disable-next-line custom-errors require( msg.sender == owner() || (address(s_configAC) != address(0) && s_configAC.hasAccess(msg.sender, msg.data)), "No access" diff --git a/contracts/src/v0.8/dev/interfaces/FlagsInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/FlagsInterface.sol rename to contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol b/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol index 65e437189a7..e18efd65ad2 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/IArbitrumDelayedInbox.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; +import {IInbox} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; /** * @notice This interface extends Arbitrum's IInbox interface to include diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol index 1d7c211bbac..672720156db 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol @@ -1,12 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/TypeAndVersionInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ -import "../CrossDomainForwarder.sol"; -import "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {iOVM_CrossDomainMessenger} from "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title OptimismCrossDomainForwarder - L1 xDomain account representation @@ -16,6 +20,7 @@ import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol */ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { // OVM_L2CrossDomainMessenger is a precompile usually deployed to 0x4200000000000000000000000000000000000007 + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i iOVM_CrossDomainMessenger private immutable OVM_CROSS_DOMAIN_MESSENGER; /** @@ -24,6 +29,7 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn */ constructor(iOVM_CrossDomainMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); OVM_CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr; } @@ -59,7 +65,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. */ modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(crossDomainMessenger()).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" @@ -72,7 +80,9 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor */ modifier onlyProposedL1Owner() override { address messenger = crossDomainMessenger(); + // solhint-disable-next-line custom-errors require(msg.sender == messenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol index bd1b0b9e885..1f630a3fbde 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol @@ -1,10 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/DelegateForwarderInterface.sol"; -import "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; -import "./OptimismCrossDomainForwarder.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {OptimismCrossDomainForwarder} from "./OptimismCrossDomainForwarder.sol"; + +import {iOVM_CrossDomainMessenger} from "../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; /** * @title OptimismCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Optimism @@ -28,8 +32,6 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros * @notice versions: * * - OptimismCrossDomainForwarder 1.0.0: initial release - * - * @inheritdoc TypeAndVersionInterface */ function typeAndVersion() external pure virtual override returns (string memory) { return "OptimismCrossDomainGovernor 1.0.0"; @@ -57,9 +59,11 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros modifier onlyLocalOrCrossDomainOwner() { address messenger = crossDomainMessenger(); // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner + // solhint-disable-next-line custom-errors require(msg.sender == messenger || msg.sender == owner(), "Sender is not the L2 messenger or owner"); // 2. The L2 Messenger's caller MUST be the L1 Owner if (msg.sender == messenger) { + // solhint-disable-next-line custom-errors require( iOVM_CrossDomainMessenger(messenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner" diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index a4ef57505b5..b522a600bab 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -7,7 +7,6 @@ import {AggregatorV2V3Interface} from "../../../interfaces/AggregatorV2V3Interfa import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; -import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; import {IL2CrossDomainMessenger} from "@eth-optimism/contracts/L2/messaging/IL2CrossDomainMessenger.sol"; /** @@ -47,8 +46,11 @@ contract OptimismSequencerUptimeFeed is /// @dev Emitted when a updateStatus is called without the status changing event RoundUpdated(int256 status, uint64 updatedAt); + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 public constant override version = 1; /// @dev L1 address @@ -57,6 +59,7 @@ contract OptimismSequencerUptimeFeed is FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); mapping(uint80 => Round) private s_rounds; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i IL2CrossDomainMessenger private immutable s_l2CrossDomainMessenger; /** @@ -65,12 +68,12 @@ contract OptimismSequencerUptimeFeed is * @param initialStatus The initial status of the feed */ constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { - setL1Sender(l1SenderAddress); + _setL1Sender(l1SenderAddress); s_l2CrossDomainMessenger = IL2CrossDomainMessenger(l2CrossDomainMessengerAddr); uint64 timestamp = uint64(block.timestamp); // Initialise roundId == 1 as the first round - recordRound(1, initialStatus, timestamp); + _recordRound(1, initialStatus, timestamp); } /** @@ -78,7 +81,7 @@ contract OptimismSequencerUptimeFeed is * @dev Mainly used for AggregatorV2V3Interface functions * @param roundId Round ID to check */ - function isValidRound(uint256 roundId) private view returns (bool) { + function _isValidRound(uint256 roundId) private view returns (bool) { return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; } @@ -104,11 +107,11 @@ contract OptimismSequencerUptimeFeed is * @param to new L1 sender that will be allowed to call `updateStatus` on this contract */ function transferL1Sender(address to) external virtual onlyOwner { - setL1Sender(to); + _setL1Sender(to); } /// @notice internal method that stores the L1 sender - function setL1Sender(address to) private { + function _setL1Sender(address to) private { address from = s_l1Sender; if (from != to) { s_l1Sender = to; @@ -121,7 +124,7 @@ contract OptimismSequencerUptimeFeed is * * @param status The status flag to convert to an aggregator-compatible answer */ - function getStatusAnswer(bool status) private pure returns (int256) { + function _getStatusAnswer(bool status) private pure returns (int256) { return status ? int256(1) : int256(0); } @@ -132,7 +135,7 @@ contract OptimismSequencerUptimeFeed is * @param status Sequencer status * @param timestamp The L1 block timestamp of status update */ - function recordRound(uint80 roundId, bool status, uint64 timestamp) private { + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { uint64 updatedAt = uint64(block.timestamp); Round memory nextRound = Round(status, timestamp, updatedAt); FeedState memory feedState = FeedState(roundId, status, timestamp, updatedAt); @@ -141,7 +144,7 @@ contract OptimismSequencerUptimeFeed is s_feedState = feedState; emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(getStatusAnswer(status), roundId, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); } /** @@ -150,11 +153,11 @@ contract OptimismSequencerUptimeFeed is * @param roundId The round ID to update * @param status Sequencer status */ - function updateRound(uint80 roundId, bool status) private { + function _updateRound(uint80 roundId, bool status) private { uint64 updatedAt = uint64(block.timestamp); s_rounds[roundId].updatedAt = updatedAt; s_feedState.updatedAt = updatedAt; - emit RoundUpdated(getStatusAnswer(status), updatedAt); + emit RoundUpdated(_getStatusAnswer(status), updatedAt); } /** @@ -179,17 +182,17 @@ contract OptimismSequencerUptimeFeed is } if (feedState.latestStatus == status) { - updateRound(feedState.latestRoundId, status); + _updateRound(feedState.latestRoundId, status); } else { feedState.latestRoundId += 1; - recordRound(feedState.latestRoundId, status, timestamp); + _recordRound(feedState.latestRoundId, status, timestamp); } } /// @inheritdoc AggregatorInterface function latestAnswer() external view override checkAccess returns (int256) { FeedState memory feedState = s_feedState; - return getStatusAnswer(feedState.latestStatus); + return _getStatusAnswer(feedState.latestStatus); } /// @inheritdoc AggregatorInterface @@ -206,8 +209,8 @@ contract OptimismSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - if (isValidRound(roundId)) { - return getStatusAnswer(s_rounds[uint80(roundId)].status); + if (_isValidRound(roundId)) { + return _getStatusAnswer(s_rounds[uint80(roundId)].status); } revert NoDataPresent(); @@ -215,7 +218,7 @@ contract OptimismSequencerUptimeFeed is /// @inheritdoc AggregatorInterface function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - if (isValidRound(roundId)) { + if (_isValidRound(roundId)) { return s_rounds[uint80(roundId)].startedAt; } @@ -232,9 +235,9 @@ contract OptimismSequencerUptimeFeed is checkAccess returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) { - if (isValidRound(_roundId)) { + if (_isValidRound(_roundId)) { Round memory round = s_rounds[_roundId]; - answer = getStatusAnswer(round.status); + answer = _getStatusAnswer(round.status); startedAt = uint256(round.startedAt); roundId = _roundId; updatedAt = uint256(round.updatedAt); @@ -255,7 +258,7 @@ contract OptimismSequencerUptimeFeed is FeedState memory feedState = s_feedState; roundId = feedState.latestRoundId; - answer = getStatusAnswer(feedState.latestStatus); + answer = _getStatusAnswer(feedState.latestStatus); startedAt = feedState.startedAt; updatedAt = feedState.updatedAt; answeredInRound = roundId; diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol index c25b481166f..a955b7e92ca 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../interfaces/AggregatorValidatorInterface.sol"; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../../shared/interfaces/AccessControllerInterface.sol"; -import "../../../interfaces/AggregatorV3Interface.sol"; -import "../../../shared/access/SimpleWriteAccessController.sol"; +import {AggregatorValidatorInterface} from "../../../interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; -import "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; -import "@eth-optimism/contracts/L1/messaging/IL1CrossDomainMessenger.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; + +import {IL1CrossDomainMessenger} from "@eth-optimism/contracts/L1/messaging/IL1CrossDomainMessenger.sol"; /** * @title OptimismValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 @@ -18,7 +16,9 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf int256 private constant ANSWER_SEQ_OFFLINE = 1; uint32 private s_gasLimit; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L2_UPTIME_FEED_ADDR; /** @@ -33,7 +33,9 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf * @param gasLimit the gasLimit to use for sending a message from L1 to L2 */ constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { + // solhint-disable-next-line custom-errors require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors require(l2UptimeFeedAddr != address(0), "Invalid OptimismSequencerUptimeFeed contract address"); L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; @@ -73,12 +75,11 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf /** * @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. * @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. - * @param previousAnswer previous aggregator answer * @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. */ function validate( uint256 /* previousRoundId */, - int256 previousAnswer, + int256 /* previousAnswer */, uint256 /* currentRoundId */, int256 currentAnswer ) external override checkAccess returns (bool) { diff --git a/contracts/src/v0.8/libraries/ByteUtil.sol b/contracts/src/v0.8/libraries/ByteUtil.sol index 906fef3fa77..9691cfb7fea 100644 --- a/contracts/src/v0.8/libraries/ByteUtil.sol +++ b/contracts/src/v0.8/libraries/ByteUtil.sol @@ -16,7 +16,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint256 read from the byte array. */ - function readUint256(bytes memory data, uint256 offset) internal pure returns (uint256 result) { + function _readUint256(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 32 > data.length) revert MalformedData(); @@ -32,7 +32,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint192 read from the byte array. */ - function readUint192(bytes memory data, uint256 offset) internal pure returns (uint256 result) { + function _readUint192(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 24 > data.length) revert MalformedData(); @@ -50,7 +50,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ - function readUint32(bytes memory data, uint256 offset) internal pure returns (uint256 result) { + function _readUint32(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 4 > data.length) revert MalformedData(); @@ -68,7 +68,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ - function readAddress(bytes memory data, uint256 offset) internal pure returns (address result) { + function _readAddress(bytes memory data, uint256 offset) internal pure returns (address result) { //bounds check if (offset + 20 > data.length) revert MalformedData(); diff --git a/contracts/src/v0.8/libraries/Common.sol b/contracts/src/v0.8/libraries/Common.sol index 5bb8275c72e..fe04a9af71b 100644 --- a/contracts/src/v0.8/libraries/Common.sol +++ b/contracts/src/v0.8/libraries/Common.sol @@ -24,7 +24,7 @@ library Common { * @param recipients The array of AddressAndWeight to check * @return bool True if there are duplicates, false otherwise */ - function hasDuplicateAddresses(Common.AddressAndWeight[] memory recipients) internal pure returns (bool) { + function _hasDuplicateAddresses(Common.AddressAndWeight[] memory recipients) internal pure returns (bool) { for (uint256 i = 0; i < recipients.length; ) { for (uint256 j = i + 1; j < recipients.length; ) { if (recipients[i].addr == recipients[j].addr) { diff --git a/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol b/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol index eabae4f5729..0629d0235ee 100644 --- a/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol +++ b/contracts/src/v0.8/libraries/test/ByteUtilTest.t.sol @@ -17,7 +17,7 @@ contract ByteUtilTest is Test { function test_readUint256Max() public { //read the first 32 bytes - uint256 result = B_512.readUint256(0); + uint256 result = B_512._readUint256(0); //the result should be the max value of a uint256 assertEq(result, type(uint256).max); @@ -25,7 +25,7 @@ contract ByteUtilTest is Test { function test_readUint192Max() public { //read the first 24 bytes - uint256 result = B_512.readUint192(0); + uint256 result = B_512._readUint192(0); //the result should be the max value of a uint192 assertEq(result, type(uint192).max); @@ -33,7 +33,7 @@ contract ByteUtilTest is Test { function test_readUint32Max() public { //read the first 4 bytes - uint256 result = B_512.readUint32(0); + uint256 result = B_512._readUint32(0); //the result should be the max value of a uint32 assertEq(result, type(uint32).max); @@ -41,7 +41,7 @@ contract ByteUtilTest is Test { function test_readUint256Min() public { //read the second 32 bytes - uint256 result = B_512.readUint256(32); + uint256 result = B_512._readUint256(32); //the result should be the min value of a uint256 assertEq(result, type(uint256).min); @@ -49,7 +49,7 @@ contract ByteUtilTest is Test { function test_readUint192Min() public { //read the second 24 bytes - uint256 result = B_512.readUint192(32); + uint256 result = B_512._readUint192(32); //the result should be the min value of a uint192 assertEq(result, type(uint192).min); @@ -57,7 +57,7 @@ contract ByteUtilTest is Test { function test_readUint32Min() public { //read the second 4 bytes - uint256 result = B_512.readUint32(32); + uint256 result = B_512._readUint32(32); //the result should be the min value of a uint32 assertEq(result, type(uint32).min); @@ -65,7 +65,7 @@ contract ByteUtilTest is Test { function test_readUint256MultiWord() public { //read the first 32 bytes - uint256 result = B_512.readUint256(31); + uint256 result = B_512._readUint256(31); //the result should be the last byte from the first word (ff), and 31 bytes from the second word (0000) (0xFF...0000) assertEq(result, type(uint256).max << 248); @@ -73,7 +73,7 @@ contract ByteUtilTest is Test { function test_readUint192MultiWord() public { //read the first 24 bytes - uint256 result = B_512.readUint192(31); + uint256 result = B_512._readUint192(31); //the result should be the last byte from the first word (ff), and 23 bytes from the second word (0000) (0xFF...0000) assertEq(result, type(uint192).max << 184); @@ -81,7 +81,7 @@ contract ByteUtilTest is Test { function test_readUint32MultiWord() public { //read the first 4 bytes - uint256 result = B_512.readUint32(31); + uint256 result = B_512._readUint32(31); //the result should be the last byte from the first word (ff), and 3 bytes from the second word (0000) (0xFF...0000) assertEq(result, type(uint32).max << 24); @@ -92,7 +92,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //try and read 32 bytes from a 16 byte number - B_128.readUint256(0); + B_128._readUint256(0); } function test_readUint192WithNotEnoughBytes() public { @@ -100,7 +100,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //try and read 24 bytes from a 16 byte number - B_128.readUint192(0); + B_128._readUint192(0); } function test_readUint32WithNotEnoughBytes() public { @@ -108,7 +108,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //try and read 4 bytes from a 2 byte number - B_16.readUint32(0); + B_16._readUint32(0); } function test_readUint256WithEmptyArray() public { @@ -116,7 +116,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //read 20 bytes from an empty array - B_EMPTY.readUint256(0); + B_EMPTY._readUint256(0); } function test_readUint192WithEmptyArray() public { @@ -124,7 +124,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //read 20 bytes from an empty array - B_EMPTY.readUint192(0); + B_EMPTY._readUint192(0); } function test_readUint32WithEmptyArray() public { @@ -132,12 +132,12 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //read 20 bytes from an empty array - B_EMPTY.readUint32(0); + B_EMPTY._readUint32(0); } function test_readAddress() public { //read the first 20 bytes - address result = B_512.readAddress(0); + address result = B_512._readAddress(0); //the result should be the max value of a uint256 assertEq(result, address(type(uint160).max)); @@ -145,7 +145,7 @@ contract ByteUtilTest is Test { function test_readZeroAddress() public { //read the first 32 bytes after the first word - address result = B_512.readAddress(32); + address result = B_512._readAddress(32); //the result should be 0x00...0 assertEq(result, address(type(uint160).min)); @@ -153,7 +153,7 @@ contract ByteUtilTest is Test { function test_readAddressMultiWord() public { //read the first 20 bytes after byte 13 - address result = B_512.readAddress(13); + address result = B_512._readAddress(13); //the result should be the value last 19 bytes of the first word (ffff..) and the first byte of the second word (00) (0xFFFF..00) assertEq(result, address(type(uint160).max << 8)); @@ -164,7 +164,7 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //read 20 bytes from a 16 byte array - B_128.readAddress(0); + B_128._readAddress(0); } function test_readAddressWithEmptyArray() public { @@ -172,6 +172,6 @@ contract ByteUtilTest is Test { vm.expectRevert(MALFORMED_ERROR_SELECTOR); //read the first 20 bytes of an empty array - B_EMPTY.readAddress(0); + B_EMPTY._readAddress(0); } } diff --git a/contracts/src/v0.8/llo-feeds/RewardManager.sol b/contracts/src/v0.8/llo-feeds/RewardManager.sol index f4bd835c256..e064bff8b67 100644 --- a/contracts/src/v0.8/llo-feeds/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/RewardManager.sol @@ -5,7 +5,6 @@ import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {IRewardManager} from "./interfaces/IRewardManager.sol"; import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; -import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; import {Common} from "../libraries/Common.sol"; import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -200,7 +199,7 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac uint256 expectedWeight ) internal { //we can't update the weights if it contains duplicates - if (Common.hasDuplicateAddresses(rewardRecipientAndWeights)) revert InvalidAddress(); + if (Common._hasDuplicateAddresses(rewardRecipientAndWeights)) revert InvalidAddress(); //loop all the reward recipients and validate the weight and address uint256 totalWeight; diff --git a/contracts/src/v0.8/llo-feeds/Verifier.sol b/contracts/src/v0.8/llo-feeds/Verifier.sol index dbd5fc73abc..cd7e3d2bad6 100644 --- a/contracts/src/v0.8/llo-feeds/Verifier.sol +++ b/contracts/src/v0.8/llo-feeds/Verifier.sol @@ -173,7 +173,7 @@ contract Verifier is IVerifier, ConfirmedOwner, TypeAndVersionInterface { address private immutable i_verifierProxyAddr; /// @notice Verifier states keyed on Feed ID - mapping(bytes32 => VerifierState) s_feedVerifierStates; + mapping(bytes32 => VerifierState) internal s_feedVerifierStates; /// @param verifierProxyAddr The address of the VerifierProxy contract constructor(address verifierProxyAddr) ConfirmedOwner(msg.sender) { diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index ef46ad37853..c446150406e 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {Test} from "forge-std/Test.sol"; import {FeeManager} from "../../FeeManager.sol"; -import {IFeeManager} from "../../interfaces/IFeeManager.sol"; import {RewardManager} from "../../RewardManager.sol"; import {Common} from "../../../libraries/Common.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol index 105c140b73a..e2c9916f663 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Test} from "forge-std/Test.sol"; -import {FeeManager} from "../../FeeManager.sol"; -import {Common} from "../../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol index dcabe6e5f9d..801a1e39925 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Test} from "forge-std/Test.sol"; -import {FeeManager} from "../../FeeManager.sol"; -import {IFeeManager} from "../../interfaces/IFeeManager.sol"; import {Common} from "../../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol index 91fb42a500f..9c2bd711ed5 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Test} from "forge-std/Test.sol"; -import {FeeManager} from "../../FeeManager.sol"; import {Common} from "../../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol index 25fb804630d..3570b8824a8 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol @@ -1,9 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {Test} from "forge-std/Test.sol"; -import {FeeManager} from "../../FeeManager.sol"; -import {Common} from "../../../libraries/Common.sol"; import "./BaseFeeManager.t.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol index 5e601034bb8..3198576e8aa 100644 --- a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithConfiguredVerifierAndFeeManager} from "../verifier/BaseVerifierTest.t.sol"; -import {Verifier} from "../../Verifier.sol"; import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; import {Common} from "../../../libraries/Common.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol index befe6bfce93..9cee5b05c57 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; -import {Common} from "../../../libraries/Common.sol"; import {RewardManager} from "../../RewardManager.sol"; import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/mocks/ERC20Mock.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol index 5dcf1eeae4f..0f94805da69 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; -import {Common} from "../../../libraries/Common.sol"; import {IRewardManager} from "../../interfaces/IRewardManager.sol"; /** diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol index 58cce9a9154..0e45ba00da4 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; import {Common} from "../../../libraries/Common.sol"; -import {RewardManager} from "../../RewardManager.sol"; /** * @title BaseRewardManagerTest diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol index e6f964f9f9f..4b3063ac016 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol"; import {Common} from "../../../libraries/Common.sol"; -import {RewardManager} from "../../RewardManager.sol"; /** * @title BaseRewardManagerTest diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol index 641d2772595..8838beded9d 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; contract VerifierActivateConfigTest is BaseTestWithConfiguredVerifierAndFeeManager { function test_revertsIfNotOwner() public { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol index fc6814d3bfe..70e65a60300 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; contract VerifierActivateFeedTest is BaseTestWithConfiguredVerifierAndFeeManager { function test_revertsIfNotOwnerActivateFeed() public { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol index 7de7dea03d1..8410d655897 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {BaseTest} from "./BaseVerifierTest.t.sol"; -import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol index 66ddb4bf3c3..f73d93af18c 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol @@ -2,9 +2,7 @@ pragma solidity 0.8.16; import {BaseTest} from "./BaseVerifierTest.t.sol"; -import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; -import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; contract VerifierProxyInitializeVerifierTest is BaseTest { bytes32 latestDigest; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol index 9fa2f16d900..3699aaf420d 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol"; import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; -import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; import {Common} from "../../../libraries/Common.sol"; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol index 5aa3e791ed8..9b5f94acd4b 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol @@ -2,11 +2,7 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol"; -import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; -import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; -import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; -import {Common} from "../../../libraries/Common.sol"; import {FeeManager} from "../../FeeManager.sol"; contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAndFeeManager { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol index a64d6ee0f78..95a42e52edc 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol"; -import {IVerifier} from "../../interfaces/IVerifier.sol"; import {VerifierProxy} from "../../VerifierProxy.sol"; contract VerifierProxyUnsetVerifierTest is BaseTest { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol index 57c98622f5b..6c5eac9b6dd 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol @@ -2,8 +2,6 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; -import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; import {Common} from "../../../libraries/Common.sol"; contract VerifierSetConfigFromSourceTest is BaseTest { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol index faa1f98bc30..f0b045e7f30 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; import {Common} from "../../../libraries/Common.sol"; contract VerifierSetConfigTest is BaseTest { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol index 1b4340495fc..290eaa1d568 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import {BaseTest} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; contract VerifierConstructorTest is BaseTest { function test_revertsIfInitializedWithEmptyVerifierProxy() public { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol index fffa291b0d8..52281298d48 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol @@ -2,9 +2,6 @@ pragma solidity 0.8.16; import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol"; -import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; -import {Common} from "../../../libraries/Common.sol"; contract VerifierTestWithConfiguredVerifierAndFeeManager is BaseTestWithConfiguredVerifierAndFeeManager { uint256 internal constant DEFAULT_LINK_MINT_QUANTITY = 100 ether; diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol index 467c5072d55..41c484a8787 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.16; -import {BaseTestWithConfiguredVerifierAndFeeManager, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; +import {BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol"; import {Verifier} from "../../Verifier.sol"; -import {VerifierProxy} from "../../VerifierProxy.sol"; contract VerificationdeactivateConfigWhenThereAreMultipleDigestsTest is BaseTestWithMultipleConfiguredDigests { function test_revertsIfCalledByNonOwner() public { diff --git a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol new file mode 100644 index 00000000000..1fe5e8f0cd6 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ConfirmedOwnerWithProposal} from "../../shared/access/ConfirmedOwnerWithProposal.sol"; +import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; + +// solhint-disable custom-errors +contract AuthorizedForwarder is ConfirmedOwnerWithProposal, AuthorizedReceiver { + using Address for address; + + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable linkToken; + + event OwnershipTransferRequestedWithMessage(address indexed from, address indexed to, bytes message); + + constructor( + address link, + address owner, + address recipient, + bytes memory message + ) ConfirmedOwnerWithProposal(owner, recipient) { + require(link != address(0), "Link token cannot be a zero address"); + linkToken = link; + if (recipient != address(0)) { + emit OwnershipTransferRequestedWithMessage(owner, recipient, message); + } + } + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant typeAndVersion = "AuthorizedForwarder 1.1.0"; + + // @notice Forward a call to another contract + // @dev Only callable by an authorized sender + // @param to address + // @param data to forward + function forward(address to, bytes calldata data) external validateAuthorizedSender { + require(to != linkToken, "Cannot forward to Link token"); + _forward(to, data); + } + + // @notice Forward multiple calls to other contracts in a multicall style + // @dev Only callable by an authorized sender + // @param tos An array of addresses to forward the calls to + // @param datas An array of data to forward to each corresponding address + function multiForward(address[] calldata tos, bytes[] calldata datas) external validateAuthorizedSender { + require(tos.length == datas.length, "Arrays must have the same length"); + + for (uint256 i = 0; i < tos.length; ++i) { + address to = tos[i]; + require(to != linkToken, "Cannot forward to Link token"); + + // Perform the forward operation + _forward(to, datas[i]); + } + } + + // @notice Forward a call to another contract + // @dev Only callable by the owner + // @param to address + // @param data to forward + function ownerForward(address to, bytes calldata data) external onlyOwner { + _forward(to, data); + } + + // @notice Transfer ownership with instructions for recipient + // @param to address proposed recipient of ownership + // @param message instructions for recipient upon accepting ownership + function transferOwnershipWithMessage(address to, bytes calldata message) external { + transferOwnership(to); + emit OwnershipTransferRequestedWithMessage(msg.sender, to, message); + } + + // @notice concrete implementation of AuthorizedReceiver + // @return bool of whether sender is authorized + function _canSetAuthorizedSenders() internal view override returns (bool) { + return owner() == msg.sender; + } + + // @notice common forwarding functionality and validation + function _forward(address to, bytes calldata data) private { + require(to.isContract(), "Must forward to a contract"); + // solhint-disable-next-line avoid-low-level-calls + (bool success, bytes memory result) = to.call(data); + if (!success) { + if (result.length == 0) revert("Forwarded call reverted without reason"); + assembly { + revert(add(32, result), mload(result)) + } + } + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol new file mode 100644 index 00000000000..04d2635d583 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/AuthorizedReceiver.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AuthorizedReceiverInterface} from "../../interfaces/AuthorizedReceiverInterface.sol"; + +// solhint-disable custom-errors +abstract contract AuthorizedReceiver is AuthorizedReceiverInterface { + mapping(address sender => bool authorized) private s_authorizedSenders; + address[] private s_authorizedSenderList; + + event AuthorizedSendersChanged(address[] senders, address changedBy); + + // @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. + // @param senders The addresses of the authorized Chainlink node + function setAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter { + require(senders.length > 0, "Must have at least 1 sender"); + // Set previous authorized senders to false + uint256 authorizedSendersLength = s_authorizedSenderList.length; + for (uint256 i = 0; i < authorizedSendersLength; ++i) { + s_authorizedSenders[s_authorizedSenderList[i]] = false; + } + // Set new to true + for (uint256 i = 0; i < senders.length; ++i) { + require(s_authorizedSenders[senders[i]] == false, "Must not have duplicate senders"); + s_authorizedSenders[senders[i]] = true; + } + // Replace list + s_authorizedSenderList = senders; + emit AuthorizedSendersChanged(senders, msg.sender); + } + + // @notice Retrieve a list of authorized senders + // @return array of addresses + function getAuthorizedSenders() external view override returns (address[] memory) { + return s_authorizedSenderList; + } + + // @notice Use this to check if a node is authorized for fulfilling requests + // @param sender The address of the Chainlink node + // @return The authorization status of the node + function isAuthorizedSender(address sender) public view override returns (bool) { + return s_authorizedSenders[sender]; + } + + // @notice customizable guard of who can update the authorized sender list + // @return bool whether sender can update authorized sender list + function _canSetAuthorizedSenders() internal virtual returns (bool); + + // @notice validates the sender is an authorized sender + function _validateIsAuthorizedSender() internal view { + require(isAuthorizedSender(msg.sender), "Not authorized sender"); + } + + // @notice prevents non-authorized addresses from calling this method + modifier validateAuthorizedSender() { + _validateIsAuthorizedSender(); + _; + } + + // @notice prevents non-authorized addresses from calling this method + modifier validateAuthorizedSenderSetter() { + require(_canSetAuthorizedSenders(), "Cannot set authorized senders"); + _; + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol b/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol new file mode 100644 index 00000000000..cfde9a4d583 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/LinkTokenReceiver.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +// solhint-disable custom-errors +abstract contract LinkTokenReceiver { + // @notice Called when LINK is sent to the contract via `transferAndCall` + // @dev The data payload's first 2 words will be overwritten by the `sender` and `amount` + // values to ensure correctness. Calls oracleRequest. + // @param sender Address of the sender + // @param amount Amount of LINK sent (specified in wei) + // @param data Payload of the transaction + function onTokenTransfer( + address sender, + uint256 amount, + bytes memory data + ) public validateFromLINK permittedFunctionsForLINK(data) { + assembly { + // solhint-disable-next-line avoid-low-level-calls + mstore(add(data, 36), sender) // ensure correct sender is passed + // solhint-disable-next-line avoid-low-level-calls + mstore(add(data, 68), amount) // ensure correct amount is passed0.8.19 + } + // solhint-disable-next-line avoid-low-level-calls + (bool success, ) = address(this).delegatecall(data); // calls oracleRequest + require(success, "Unable to create request"); + } + + function getChainlinkToken() public view virtual returns (address); + + // @notice Validate the function called on token transfer + function _validateTokenTransferAction(bytes4 funcSelector, bytes memory data) internal virtual; + + // @dev Reverts if not sent from the LINK token + modifier validateFromLINK() { + require(msg.sender == getChainlinkToken(), "Must use LINK token"); + _; + } + + // @dev Reverts if the given data does not begin with the `oracleRequest` function selector + // @param data The data payload of the request + modifier permittedFunctionsForLINK(bytes memory data) { + bytes4 funcSelector; + assembly { + // solhint-disable-next-line avoid-low-level-calls + funcSelector := mload(add(data, 32)) + } + _validateTokenTransferAction(funcSelector, data); + _; + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol new file mode 100644 index 00000000000..b68e2837304 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; +import {LinkTokenReceiver} from "./LinkTokenReceiver.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {AuthorizedReceiverInterface} from "../../interfaces/AuthorizedReceiverInterface.sol"; +import {OperatorInterface} from "../../interfaces/OperatorInterface.sol"; +import {IOwnable} from "../../shared/interfaces/IOwnable.sol"; +import {WithdrawalInterface} from "./interfaces/WithdrawalInterface.sol"; +import {OracleInterface} from "../../interfaces/OracleInterface.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/SafeCast.sol"; + +// @title The Chainlink Operator contract +// @notice Node operators can deploy this contract to fulfill requests sent to them +// solhint-disable custom-errors +contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, OperatorInterface, WithdrawalInterface { + using Address for address; + + struct Commitment { + bytes31 paramsHash; + uint8 dataVersion; + } + + uint256 public constant EXPIRYTIME = 5 minutes; + uint256 private constant MAXIMUM_DATA_VERSION = 256; + uint256 private constant MINIMUM_CONSUMER_GAS_LIMIT = 400000; + uint256 private constant SELECTOR_LENGTH = 4; + uint256 private constant EXPECTED_REQUEST_WORDS = 2; + uint256 private constant MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); + // We initialize fields to 1 instead of 0 so that the first invocation + // does not cost more gas. + uint256 private constant ONE_FOR_CONSISTENT_GAS_COST = 1; + // oracleRequest is intended for version 1, enabling single word responses + bytes4 private constant ORACLE_REQUEST_SELECTOR = this.oracleRequest.selector; + // operatorRequest is intended for version 2, enabling multi-word responses + bytes4 private constant OPERATOR_REQUEST_SELECTOR = this.operatorRequest.selector; + + LinkTokenInterface internal immutable i_linkToken; + mapping(bytes32 => Commitment) private s_commitments; + mapping(address => bool) private s_owned; + // Tokens sent for requests that have not been fulfilled yet + uint256 private s_tokensInEscrow = ONE_FOR_CONSISTENT_GAS_COST; + + event OracleRequest( + bytes32 indexed specId, + address requester, + bytes32 requestId, + uint256 payment, + address callbackAddr, + bytes4 callbackFunctionId, + uint256 cancelExpiration, + uint256 dataVersion, + bytes data + ); + + event CancelOracleRequest(bytes32 indexed requestId); + + event OracleResponse(bytes32 indexed requestId); + + event OwnableContractAccepted(address indexed acceptedContract); + + event TargetsUpdatedAuthorizedSenders(address[] targets, address[] senders, address changedBy); + + // @notice Deploy with the address of the LINK token + // @dev Sets the LinkToken address for the imported LinkTokenInterface + // @param link The address of the LINK token + // @param owner The address of the owner + constructor(address link, address owner) ConfirmedOwner(owner) { + i_linkToken = LinkTokenInterface(link); // external but already deployed and unalterable + } + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant typeAndVersion = "Operator 1.0.0"; + + // @notice Creates the Chainlink request. This is a backwards compatible API + // with the Oracle.sol contract, but the behavior changes because + // callbackAddress is assumed to be the same as the request sender. + // @param callbackAddress The consumer of the request + // @param payment The amount of payment given (specified in wei) + // @param specId The Job Specification ID + // @param callbackAddress The address the oracle data will be sent to + // @param callbackFunctionId The callback function ID for the response + // @param nonce The nonce sent by the requester + // @param dataVersion The specified data version + // @param data The extra request parameters + function oracleRequest( + address sender, + uint256 payment, + bytes32 specId, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 nonce, + uint256 dataVersion, + bytes calldata data + ) external override validateFromLINK { + (bytes32 requestId, uint256 expiration) = _verifyAndProcessOracleRequest( + sender, + payment, + callbackAddress, + callbackFunctionId, + nonce, + dataVersion + ); + emit OracleRequest(specId, sender, requestId, payment, sender, callbackFunctionId, expiration, dataVersion, data); + } + + // @notice Creates the Chainlink request + // @dev Stores the hash of the params as the on-chain commitment for the request. + // Emits OracleRequest event for the Chainlink node to detect. + // @param sender The sender of the request + // @param payment The amount of payment given (specified in wei) + // @param specId The Job Specification ID + // @param callbackFunctionId The callback function ID for the response + // @param nonce The nonce sent by the requester + // @param dataVersion The specified data version + // @param data The extra request parameters + function operatorRequest( + address sender, + uint256 payment, + bytes32 specId, + bytes4 callbackFunctionId, + uint256 nonce, + uint256 dataVersion, + bytes calldata data + ) external override validateFromLINK { + (bytes32 requestId, uint256 expiration) = _verifyAndProcessOracleRequest( + sender, + payment, + sender, + callbackFunctionId, + nonce, + dataVersion + ); + emit OracleRequest(specId, sender, requestId, payment, sender, callbackFunctionId, expiration, dataVersion, data); + } + + // @notice Called by the Chainlink node to fulfill requests + // @dev Given params must hash back to the commitment stored from `oracleRequest`. + // Will call the callback address' callback function without bubbling up error + // checking in a `require` so that the node can get paid. + // @param requestId The fulfillment request ID that must match the requester's + // @param payment The payment amount that will be released for the oracle (specified in wei) + // @param callbackAddress The callback address to call for fulfillment + // @param callbackFunctionId The callback function ID to use for fulfillment + // @param expiration The expiration that the node should respond by before the requester can cancel + // @param data The data to return to the consuming contract + // @return Status if the external call was successful + function fulfillOracleRequest( + bytes32 requestId, + uint256 payment, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 expiration, + bytes32 data + ) + external + override + validateAuthorizedSender + validateRequestId(requestId) + validateCallbackAddress(callbackAddress) + returns (bool) + { + _verifyOracleRequestAndProcessPayment(requestId, payment, callbackAddress, callbackFunctionId, expiration, 1); + emit OracleResponse(requestId); + require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); + // All updates to the oracle's fulfillment should come before calling the + // callback(addr+functionId) as it is untrusted. + // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern + (bool success, ) = callbackAddress.call(abi.encodeWithSelector(callbackFunctionId, requestId, data)); // solhint-disable-line avoid-low-level-calls + return success; + } + + // @notice Called by the Chainlink node to fulfill requests with multi-word support + // @dev Given params must hash back to the commitment stored from `oracleRequest`. + // Will call the callback address' callback function without bubbling up error + // checking in a `require` so that the node can get paid. + // @param requestId The fulfillment request ID that must match the requester's + // @param payment The payment amount that will be released for the oracle (specified in wei) + // @param callbackAddress The callback address to call for fulfillment + // @param callbackFunctionId The callback function ID to use for fulfillment + // @param expiration The expiration that the node should respond by before the requester can cancel + // @param data The data to return to the consuming contract + // @return Status if the external call was successful + function fulfillOracleRequest2( + bytes32 requestId, + uint256 payment, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 expiration, + bytes calldata data + ) + external + override + validateAuthorizedSender + validateRequestId(requestId) + validateCallbackAddress(callbackAddress) + validateMultiWordResponseId(requestId, data) + returns (bool) + { + _verifyOracleRequestAndProcessPayment(requestId, payment, callbackAddress, callbackFunctionId, expiration, 2); + emit OracleResponse(requestId); + require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas"); + // All updates to the oracle's fulfillment should come before calling the + // callback(addr+functionId) as it is untrusted. + // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern + (bool success, ) = callbackAddress.call(abi.encodePacked(callbackFunctionId, data)); // solhint-disable-line avoid-low-level-calls + return success; + } + + // @notice Transfer the ownership of ownable contracts. This is primarily + // intended for Authorized Forwarders but could possibly be extended to work + // with future contracts.OracleInterface + // @param ownable list of addresses to transfer + // @param newOwner address to transfer ownership to + function transferOwnableContracts(address[] calldata ownable, address newOwner) external onlyOwner { + for (uint256 i = 0; i < ownable.length; ++i) { + s_owned[ownable[i]] = false; + IOwnable(ownable[i]).transferOwnership(newOwner); + } + } + + // @notice Accept the ownership of an ownable contract. This is primarily + // intended for Authorized Forwarders but could possibly be extended to work + // with future contracts. + // @dev Must be the pending owner on the contract + // @param ownable list of addresses of Ownable contracts to accept + function acceptOwnableContracts(address[] calldata ownable) public validateAuthorizedSenderSetter { + for (uint256 i = 0; i < ownable.length; ++i) { + s_owned[ownable[i]] = true; + emit OwnableContractAccepted(ownable[i]); + IOwnable(ownable[i]).acceptOwnership(); + } + } + + // @notice Sets the fulfillment permission for + // @param targets The addresses to set permissions on + // @param senders The addresses that are allowed to send updates + function setAuthorizedSendersOn( + address[] calldata targets, + address[] calldata senders + ) public validateAuthorizedSenderSetter { + emit TargetsUpdatedAuthorizedSenders(targets, senders, msg.sender); + + for (uint256 i = 0; i < targets.length; ++i) { + AuthorizedReceiverInterface(targets[i]).setAuthorizedSenders(senders); + } + } + + // @notice Accepts ownership of ownable contracts and then immediately sets + // the authorized sender list on each of the newly owned contracts. This is + // primarily intended for Authorized Forwarders but could possibly be + // extended to work with future contracts. + // @param targets The addresses to set permissions on + // @param senders The addresses that are allowed to send updates + function acceptAuthorizedReceivers( + address[] calldata targets, + address[] calldata senders + ) external validateAuthorizedSenderSetter { + acceptOwnableContracts(targets); + setAuthorizedSendersOn(targets, senders); + } + + // @notice Allows the node operator to withdraw earned LINK to a given address + // @dev The owner of the contract can be another wallet and does not have to be a Chainlink node + // @param recipient The address to send the LINK token to + // @param amount The amount to send (specified in wei) + function withdraw( + address recipient, + uint256 amount + ) external override(OracleInterface, WithdrawalInterface) onlyOwner validateAvailableFunds(amount) { + assert(i_linkToken.transfer(recipient, amount)); + } + + // @notice Displays the amount of LINK that is available for the node operator to withdraw + // @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage + // @return The amount of withdrawable LINK on the contract + function withdrawable() external view override(OracleInterface, WithdrawalInterface) returns (uint256) { + return _fundsAvailable(); + } + + // @notice Forward a call to another contract + // @dev Only callable by the owner + // @param to address + // @param data to forward + function ownerForward(address to, bytes calldata data) external onlyOwner validateNotToLINK(to) { + require(to.isContract(), "Must forward to a contract"); + // solhint-disable-next-line avoid-low-level-calls + (bool status, ) = to.call(data); + require(status, "Forwarded call failed"); + } + + // @notice Interact with other LinkTokenReceiver contracts by calling transferAndCall + // @param to The address to transfer to. + // @param value The amount to be transferred. + // @param data The extra data to be passed to the receiving contract. + // @return success bool + function ownerTransferAndCall( + address to, + uint256 value, + bytes calldata data + ) external override onlyOwner validateAvailableFunds(value) returns (bool success) { + return i_linkToken.transferAndCall(to, value, data); + } + + // @notice Distribute funds to multiple addresses using ETH send + // to this payable function. + // @dev Array length must be equal, ETH sent must equal the sum of amounts. + // A malicious receiver could cause the distribution to revert, in which case + // it is expected that the address is removed from the list. + // @param receivers list of addresses + // @param amounts list of amounts + function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable { + require(receivers.length > 0 && receivers.length == amounts.length, "Invalid array length(s)"); + uint256 valueRemaining = msg.value; + for (uint256 i = 0; i < receivers.length; ++i) { + uint256 sendAmount = amounts[i]; + valueRemaining = valueRemaining - sendAmount; + receivers[i].transfer(sendAmount); + } + require(valueRemaining == 0, "Too much ETH sent"); + } + + // @notice Allows recipient to cancel requests sent to this oracle contract. + // Will transfer the LINK sent for the request back to the recipient address. + // @dev Given params must hash to a commitment stored on the contract in order + // for the request to be valid. Emits CancelOracleRequest event. + // @param requestId The request ID + // @param payment The amount of payment given (specified in wei) + // @param callbackFunc The requester's specified callback function selector + // @param expiration The time of the expiration for the request + function cancelOracleRequest( + bytes32 requestId, + uint256 payment, + bytes4 callbackFunc, + uint256 expiration + ) external override { + bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); + require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); + // solhint-disable-next-line not-rely-on-time + require(expiration <= block.timestamp, "Request is not expired"); + + delete s_commitments[requestId]; + emit CancelOracleRequest(requestId); + + i_linkToken.transfer(msg.sender, payment); + } + + // @notice Allows requester to cancel requests sent to this oracle contract. + // Will transfer the LINK sent for the request back to the recipient address. + // @dev Given params must hash to a commitment stored on the contract in order + // for the request to be valid. Emits CancelOracleRequest event. + // @param nonce The nonce used to generate the request ID + // @param payment The amount of payment given (specified in wei) + // @param callbackFunc The requester's specified callback function selector + // @param expiration The time of the expiration for the request + function cancelOracleRequestByRequester( + uint256 nonce, + uint256 payment, + bytes4 callbackFunc, + uint256 expiration + ) external { + bytes32 requestId = keccak256(abi.encodePacked(msg.sender, nonce)); + bytes31 paramsHash = _buildParamsHash(payment, msg.sender, callbackFunc, expiration); + require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); + // solhint-disable-next-line not-rely-on-time + require(expiration <= block.timestamp, "Request is not expired"); + + delete s_commitments[requestId]; + emit CancelOracleRequest(requestId); + + i_linkToken.transfer(msg.sender, payment); + } + + // @notice Returns the address of the LINK token + // @dev This is the public implementation for chainlinkTokenAddress, which is + // an internal method of the ChainlinkClient contract + function getChainlinkToken() public view override returns (address) { + return address(i_linkToken); + } + + // @notice Require that the token transfer action is valid + // @dev OPERATOR_REQUEST_SELECTOR = multiword, ORACLE_REQUEST_SELECTOR = singleword + function _validateTokenTransferAction(bytes4 funcSelector, bytes memory data) internal pure override { + require(data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); + require( + funcSelector == OPERATOR_REQUEST_SELECTOR || funcSelector == ORACLE_REQUEST_SELECTOR, + "Must use whitelisted functions" + ); + } + + // @notice Verify the Oracle Request and record necessary information + // @param sender The sender of the request + // @param payment The amount of payment given (specified in wei) + // @param callbackAddress The callback address for the response + // @param callbackFunctionId The callback function ID for the response + // @param nonce The nonce sent by the requester + function _verifyAndProcessOracleRequest( + address sender, + uint256 payment, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 nonce, + uint256 dataVersion + ) private validateNotToLINK(callbackAddress) returns (bytes32 requestId, uint256 expiration) { + requestId = keccak256(abi.encodePacked(sender, nonce)); + require(s_commitments[requestId].paramsHash == 0, "Must use a unique ID"); + // solhint-disable-next-line not-rely-on-time + expiration = block.timestamp + EXPIRYTIME; + bytes31 paramsHash = _buildParamsHash(payment, callbackAddress, callbackFunctionId, expiration); + s_commitments[requestId] = Commitment(paramsHash, SafeCast.toUint8(dataVersion)); + s_tokensInEscrow = s_tokensInEscrow + payment; + return (requestId, expiration); + } + + // @notice Verify the Oracle request and unlock escrowed payment + // @param requestId The fulfillment request ID that must match the requester's + // @param payment The payment amount that will be released for the oracle (specified in wei) + // @param callbackAddress The callback address to call for fulfillment + // @param callbackFunctionId The callback function ID to use for fulfillment + // @param expiration The expiration that the node should respond by before the requester can cancel + function _verifyOracleRequestAndProcessPayment( + bytes32 requestId, + uint256 payment, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 expiration, + uint256 dataVersion + ) internal { + bytes31 paramsHash = _buildParamsHash(payment, callbackAddress, callbackFunctionId, expiration); + require(s_commitments[requestId].paramsHash == paramsHash, "Params do not match request ID"); + require(s_commitments[requestId].dataVersion <= SafeCast.toUint8(dataVersion), "Data versions must match"); + s_tokensInEscrow = s_tokensInEscrow - payment; + delete s_commitments[requestId]; + } + + // @notice Build the bytes31 hash from the payment, callback and expiration. + // @param payment The payment amount that will be released for the oracle (specified in wei) + // @param callbackAddress The callback address to call for fulfillment + // @param callbackFunctionId The callback function ID to use for fulfillment + // @param expiration The expiration that the node should respond by before the requester can cancel + // @return hash bytes31 + function _buildParamsHash( + uint256 payment, + address callbackAddress, + bytes4 callbackFunctionId, + uint256 expiration + ) internal pure returns (bytes31) { + return bytes31(keccak256(abi.encodePacked(payment, callbackAddress, callbackFunctionId, expiration))); + } + + // @notice Returns the LINK available in this contract, not locked in escrow + // @return uint256 LINK tokens available + function _fundsAvailable() private view returns (uint256) { + return i_linkToken.balanceOf(address(this)) - (s_tokensInEscrow - ONE_FOR_CONSISTENT_GAS_COST); + } + + // @notice concrete implementation of AuthorizedReceiver + // @return bool of whether sender is authorized + function _canSetAuthorizedSenders() internal view override returns (bool) { + return isAuthorizedSender(msg.sender) || owner() == msg.sender; + } + + // MODIFIERS + + // @dev Reverts if the first 32 bytes of the bytes array is not equal to requestId + // @param requestId bytes32 + // @param data bytes + modifier validateMultiWordResponseId(bytes32 requestId, bytes calldata data) { + require(data.length >= 32, "Response must be > 32 bytes"); + bytes32 firstDataWord; + assembly { + firstDataWord := calldataload(data.offset) + } + require(requestId == firstDataWord, "First word must be requestId"); + _; + } + + // @dev Reverts if amount requested is greater than withdrawable balance + // @param amount The given amount to compare to `s_withdrawableTokens` + modifier validateAvailableFunds(uint256 amount) { + require(_fundsAvailable() >= amount, "Amount requested is greater than withdrawable balance"); + _; + } + + // @dev Reverts if request ID does not exist + // @param requestId The given request ID to check in stored `commitments` + modifier validateRequestId(bytes32 requestId) { + require(s_commitments[requestId].paramsHash != 0, "Must have a valid requestId"); + _; + } + + // @dev Reverts if the callback address is the LINK token + // @param to The callback address + modifier validateNotToLINK(address to) { + require(to != address(i_linkToken), "Cannot call to LINK"); + _; + } + + // @dev Reverts if the target address is owned by the operator + modifier validateCallbackAddress(address callbackAddress) { + require(!s_owned[callbackAddress], "Cannot call owned contract"); + _; + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol new file mode 100644 index 00000000000..62ace2451c5 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {Operator} from "./Operator.sol"; +import {AuthorizedForwarder} from "./AuthorizedForwarder.sol"; + +// @title Operator Factory +// @notice Creates Operator contracts for node operators +// solhint-disable custom-errors +contract OperatorFactory { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable linkToken; + mapping(address => bool) private s_created; + + event OperatorCreated(address indexed operator, address indexed owner, address indexed sender); + event AuthorizedForwarderCreated(address indexed forwarder, address indexed owner, address indexed sender); + + // @param linkAddress address + constructor(address linkAddress) { + linkToken = linkAddress; + } + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant typeAndVersion = "OperatorFactory 1.0.0"; + + // @notice creates a new Operator contract with the msg.sender as owner + function deployNewOperator() external returns (address) { + Operator operator = new Operator(linkToken, msg.sender); + + s_created[address(operator)] = true; + emit OperatorCreated(address(operator), msg.sender, msg.sender); + + return address(operator); + } + + // @notice creates a new Operator contract with the msg.sender as owner and a + // new Operator Forwarder with the Operator as the owner + function deployNewOperatorAndForwarder() external returns (address, address) { + Operator operator = new Operator(linkToken, msg.sender); + s_created[address(operator)] = true; + emit OperatorCreated(address(operator), msg.sender, msg.sender); + + AuthorizedForwarder forwarder = new AuthorizedForwarder(linkToken, address(this), address(operator), new bytes(0)); + s_created[address(forwarder)] = true; + emit AuthorizedForwarderCreated(address(forwarder), address(this), msg.sender); + + return (address(operator), address(forwarder)); + } + + // @notice creates a new Forwarder contract with the msg.sender as owner + function deployNewForwarder() external returns (address) { + AuthorizedForwarder forwarder = new AuthorizedForwarder(linkToken, msg.sender, address(0), new bytes(0)); + + s_created[address(forwarder)] = true; + emit AuthorizedForwarderCreated(address(forwarder), msg.sender, msg.sender); + + return address(forwarder); + } + + // @notice creates a new Forwarder contract with the msg.sender as owner + function deployNewForwarderAndTransferOwnership(address to, bytes calldata message) external returns (address) { + AuthorizedForwarder forwarder = new AuthorizedForwarder(linkToken, msg.sender, to, message); + + s_created[address(forwarder)] = true; + emit AuthorizedForwarderCreated(address(forwarder), msg.sender, msg.sender); + + return address(forwarder); + } + + // @notice indicates whether this factory deployed an address + function created(address query) external view returns (bool) { + return s_created[query]; + } +} diff --git a/contracts/src/v0.8/operatorforwarder/dev/interfaces/WithdrawalInterface.sol b/contracts/src/v0.8/operatorforwarder/dev/interfaces/WithdrawalInterface.sol new file mode 100644 index 00000000000..c064b0627b5 --- /dev/null +++ b/contracts/src/v0.8/operatorforwarder/dev/interfaces/WithdrawalInterface.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface WithdrawalInterface { + // @notice transfer LINK held by the contract belonging to msg.sender to + // another address + // @param recipient is the address to send the LINK to + // @param amount is the amount of LINK to send + function withdraw(address recipient, uint256 amount) external; + + // @notice query the available amount of LINK to withdraw by msg.sender + function withdrawable() external view returns (uint256); +} diff --git a/contracts/src/v0.8/shared/access/ConfirmedOwner.sol b/contracts/src/v0.8/shared/access/ConfirmedOwner.sol index a33cff10bc9..a25d92ffd67 100644 --- a/contracts/src/v0.8/shared/access/ConfirmedOwner.sol +++ b/contracts/src/v0.8/shared/access/ConfirmedOwner.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./ConfirmedOwnerWithProposal.sol"; +import {ConfirmedOwnerWithProposal} from "./ConfirmedOwnerWithProposal.sol"; /** * @title The ConfirmedOwner contract diff --git a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol index c2a01cfca18..a6757c38869 100644 --- a/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol +++ b/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../interfaces/IOwnable.sol"; +import {IOwnable} from "../interfaces/IOwnable.sol"; /** * @title The ConfirmedOwner contract @@ -15,6 +15,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { event OwnershipTransferred(address indexed from, address indexed to); constructor(address newOwner, address pendingOwner) { + // solhint-disable-next-line custom-errors require(newOwner != address(0), "Cannot set owner to zero"); s_owner = newOwner; @@ -35,6 +36,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { * @notice Allows an ownership transfer to be completed by the recipient. */ function acceptOwnership() external override { + // solhint-disable-next-line custom-errors require(msg.sender == s_pendingOwner, "Must be proposed owner"); address oldOwner = s_owner; @@ -55,6 +57,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { * @notice validate, transfer ownership, and emit relevant events */ function _transferOwnership(address to) private { + // solhint-disable-next-line custom-errors require(to != msg.sender, "Cannot transfer to self"); s_pendingOwner = to; @@ -66,6 +69,7 @@ contract ConfirmedOwnerWithProposal is IOwnable { * @notice validate access */ function _validateOwnership() internal view { + // solhint-disable-next-line custom-errors require(msg.sender == s_owner, "Only callable by owner"); } diff --git a/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol b/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol index ade1c15c86b..b36fa4e4b60 100644 --- a/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol +++ b/contracts/src/v0.8/shared/access/SimpleReadAccessController.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./SimpleWriteAccessController.sol"; +import {SimpleWriteAccessController} from "./SimpleWriteAccessController.sol"; /** * @title SimpleReadAccessController @@ -20,6 +20,7 @@ contract SimpleReadAccessController is SimpleWriteAccessController { * @param _user The address to query */ function hasAccess(address _user, bytes memory _calldata) public view virtual override returns (bool) { + // solhint-disable-next-line avoid-tx-origin return super.hasAccess(_user, _calldata) || _user == tx.origin; } } diff --git a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol index c73dec470b2..117d2e77dd6 100644 --- a/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol +++ b/contracts/src/v0.8/shared/access/SimpleWriteAccessController.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./ConfirmedOwner.sol"; -import "../interfaces/AccessControllerInterface.sol"; +import {ConfirmedOwner} from "./ConfirmedOwner.sol"; +import {AccessControllerInterface} from "../interfaces/AccessControllerInterface.sol"; /** * @title SimpleWriteAccessController @@ -13,7 +13,7 @@ import "../interfaces/AccessControllerInterface.sol"; */ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwner { bool public checkEnabled; - mapping(address => bool) internal accessList; + mapping(address => bool) internal s_accessList; event AddedAccess(address user); event RemovedAccess(address user); @@ -29,7 +29,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne * @param _user The address to query */ function hasAccess(address _user, bytes memory) public view virtual override returns (bool) { - return accessList[_user] || !checkEnabled; + return s_accessList[_user] || !checkEnabled; } /** @@ -37,8 +37,8 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne * @param _user The address to add */ function addAccess(address _user) external onlyOwner { - if (!accessList[_user]) { - accessList[_user] = true; + if (!s_accessList[_user]) { + s_accessList[_user] = true; emit AddedAccess(_user); } @@ -49,8 +49,8 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne * @param _user The address to remove */ function removeAccess(address _user) external onlyOwner { - if (accessList[_user]) { - accessList[_user] = false; + if (s_accessList[_user]) { + s_accessList[_user] = false; emit RemovedAccess(_user); } @@ -82,6 +82,7 @@ contract SimpleWriteAccessController is AccessControllerInterface, ConfirmedOwne * @dev reverts if the caller does not have access */ modifier checkAccess() { + // solhint-disable-next-line custom-errors require(hasAccess(msg.sender, msg.data), "No access"); _; } diff --git a/contracts/src/v0.8/shared/interfaces/IWERC20.sol b/contracts/src/v0.8/shared/interfaces/IWERC20.sol index e79712a593d..96073530482 100644 --- a/contracts/src/v0.8/shared/interfaces/IWERC20.sol +++ b/contracts/src/v0.8/shared/interfaces/IWERC20.sol @@ -4,5 +4,5 @@ pragma solidity ^0.8.0; interface IWERC20 { function deposit() external payable; - function withdraw(uint) external; + function withdraw(uint256) external; } diff --git a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol index 11bdb790c02..02c13be9937 100644 --- a/contracts/src/v0.8/shared/mocks/WERC20Mock.sol +++ b/contracts/src/v0.8/shared/mocks/WERC20Mock.sol @@ -6,8 +6,8 @@ import {ERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/E contract WERC20Mock is ERC20 { constructor() ERC20("WERC20Mock", "WERC") {} - event Deposit(address indexed dst, uint wad); - event Withdrawal(address indexed src, uint wad); + event Deposit(address indexed dst, uint256 wad); + event Withdrawal(address indexed src, uint256 wad); receive() external payable { deposit(); @@ -18,7 +18,8 @@ contract WERC20Mock is ERC20 { emit Deposit(msg.sender, msg.value); } - function withdraw(uint wad) public { + function withdraw(uint256 wad) public { + // solhint-disable-next-line custom-errors, reason-string require(balanceOf(msg.sender) >= wad); _burn(msg.sender, wad); payable(msg.sender).transfer(wad); diff --git a/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol b/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol index 5031a528b3d..1f19d0de54e 100644 --- a/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Abstract.sol @@ -5,8 +5,11 @@ import {ITypeAndVersion} from "../interfaces/ITypeAndVersion.sol"; abstract contract OCR2Abstract is ITypeAndVersion { // Maximum number of oracles the offchain reporting protocol is designed for + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 internal constant maxNumOracles = 31; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 private constant prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables uint256 private constant prefix = 0x0001 << (256 - 16); // 0x000100..00 /** diff --git a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Base.sol b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol similarity index 91% rename from contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Base.sol rename to contracts/src/v0.8/shared/ocr2/OCR2Base.sol index 0814311248c..0f0317602d3 100644 --- a/contracts/src/v0.8/functions/dev/v0_0_0/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/shared/ocr2/OCR2Base.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ConfirmedOwner} from "../../../../shared/access/ConfirmedOwner.sol"; +import {ConfirmedOwner} from "../access/ConfirmedOwner.sol"; import {OCR2Abstract} from "./OCR2Abstract.sol"; /** @@ -14,6 +14,7 @@ import {OCR2Abstract} from "./OCR2Abstract.sol"; * will be folded directly into the application contract. Inheritance prevents us from doing lots * of juicy storage layout optimizations, leading to a substantial increase in gas cost. */ +// solhint-disable custom-errors abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { error ReportInvalid(); @@ -23,8 +24,6 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { i_uniqueReports = uniqueReports; } - uint256 private constant maxUint32 = (1 << 32) - 1; - // Storing these fields used on the hot path in a ConfigInfo variable reduces the // retrieval of all of them to a single SLOAD. If any further fields are // added, make sure that storage of the struct still takes at most 32 bytes. @@ -159,7 +158,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { s_latestConfigBlockNumber = uint32(block.number); s_configCount += 1; { - s_configInfo.latestConfigDigest = configDigestFromConfigData( + s_configInfo.latestConfigDigest = _configDigestFromConfigData( block.chainid, address(this), s_configCount, @@ -188,37 +187,6 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { _afterSetConfig(args.f, args.onchainConfig); } - function configDigestFromConfigData( - uint256 _chainId, - address _contractAddress, - uint64 _configCount, - address[] memory _signers, - address[] memory _transmitters, - uint8 _f, - bytes memory _onchainConfig, - uint64 _encodedConfigVersion, - bytes memory _encodedConfig - ) internal pure returns (bytes32) { - uint256 h = uint256( - keccak256( - abi.encode( - _chainId, - _contractAddress, - _configCount, - _signers, - _transmitters, - _f, - _onchainConfig, - _encodedConfigVersion, - _encodedConfig - ) - ) - ); - uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 - uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 - return bytes32((prefix & prefixMask) | (h & ~prefixMask)); - } - /** * @notice information about current offchain reporting protocol configuration * @return configCount ordinal number of current config, out of all configs applied to this contract so far @@ -290,7 +258,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { 32 + // word containing length of ss 0; // placeholder - function requireExpectedMsgDataLength( + function _requireExpectedMsgDataLength( bytes calldata report, bytes32[] calldata rs, bytes32[] calldata ss @@ -341,7 +309,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { ConfigInfo memory configInfo = s_configInfo; require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); - requireExpectedMsgDataLength(report, rs, ss); + _requireExpectedMsgDataLength(report, rs, ss); uint256 expectedNumSignatures; if (i_uniqueReports) { diff --git a/contracts/src/v0.8/dev/ocr2/README.md b/contracts/src/v0.8/shared/ocr2/README.md similarity index 100% rename from contracts/src/v0.8/dev/ocr2/README.md rename to contracts/src/v0.8/shared/ocr2/README.md diff --git a/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol b/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol index 6b223f51236..6b13f390009 100644 --- a/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol +++ b/contracts/src/v0.8/shared/test/token/ERC677/BurnMintERC677.t.sol @@ -8,7 +8,6 @@ import {BaseTest} from "../../BaseTest.t.sol"; import {BurnMintERC677} from "../../../token/ERC677/BurnMintERC677.sol"; import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol"; -import {Strings} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/Strings.sol"; import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; contract BurnMintERC677Setup is BaseTest { diff --git a/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol b/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol index 79441cf89f7..6362d9e78ac 100644 --- a/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol +++ b/contracts/src/v0.8/shared/token/ERC20/IOptimismMintableERC20.sol @@ -1,4 +1,5 @@ // SPDX-License-Identifier: MIT +// solhint-disable one-contract-per-file pragma solidity ^0.8.0; import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/introspection/IERC165.sol"; diff --git a/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol b/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol index 0d78581b13c..775d5fb3d94 100644 --- a/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/BurnMintERC677.sol @@ -91,6 +91,7 @@ contract BurnMintERC677 is IBurnMintERC20, ERC677, IERC165, ERC20Burnable, Owner /// @dev Reverts with an empty revert to be compatible with the existing link token when /// the recipient is this contract address. modifier validAddress(address recipient) virtual { + // solhint-disable-next-line reason-string, custom-errors if (recipient == address(this)) revert(); _; } diff --git a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol index de124d53c55..c9a2996e8e9 100644 --- a/contracts/src/v0.8/shared/token/ERC677/ERC677.sol +++ b/contracts/src/v0.8/shared/token/ERC677/ERC677.sol @@ -13,7 +13,7 @@ contract ERC677 is IERC677, ERC20 { constructor(string memory name, string memory symbol) ERC20(name, symbol) {} /// @inheritdoc IERC677 - function transferAndCall(address to, uint amount, bytes memory data) public returns (bool success) { + function transferAndCall(address to, uint256 amount, bytes memory data) public returns (bool success) { super.transfer(to, amount); emit Transfer(msg.sender, to, amount, data); if (to.isContract()) { diff --git a/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol b/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol index 38b5817d05b..a344138a17d 100644 --- a/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol +++ b/contracts/src/v0.8/tests/ChainlinkClientTestHelper.sol @@ -5,21 +5,21 @@ import "../ChainlinkClient.sol"; contract ChainlinkClientTestHelper is ChainlinkClient { constructor(address _link, address _oracle) { - setChainlinkToken(_link); - setChainlinkOracle(_oracle); + _setChainlinkToken(_link); + _setChainlinkOracle(_oracle); } event Request(bytes32 id, address callbackAddress, bytes4 callbackfunctionSelector, bytes data); event LinkAmount(uint256 amount); function publicNewRequest(bytes32 _id, address _address, bytes memory _fulfillmentSignature) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + Chainlink.Request memory req = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); emit Request(req.id, req.callbackAddress, req.callbackFunctionId, req.buf.buf); } function publicRequest(bytes32 _id, address _address, bytes memory _fulfillmentSignature, uint256 _wei) public { - Chainlink.Request memory req = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequest(req, _wei); + Chainlink.Request memory req = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + _sendChainlinkRequest(req, _wei); } function publicRequestRunTo( @@ -29,13 +29,13 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes memory _fulfillmentSignature, uint256 _wei ) public { - Chainlink.Request memory run = buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); - sendChainlinkRequestTo(_oracle, run, _wei); + Chainlink.Request memory run = _buildChainlinkRequest(_id, _address, bytes4(keccak256(_fulfillmentSignature))); + _sendChainlinkRequestTo(_oracle, run, _wei); } function publicRequestOracleData(bytes32 _id, bytes memory _fulfillmentSignature, uint256 _wei) public { - Chainlink.Request memory req = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequest(req, _wei); + Chainlink.Request memory req = _buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); + _sendOperatorRequest(req, _wei); } function publicRequestOracleDataFrom( @@ -44,8 +44,8 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes memory _fulfillmentSignature, uint256 _wei ) public { - Chainlink.Request memory run = buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); - sendOperatorRequestTo(_oracle, run, _wei); + Chainlink.Request memory run = _buildOperatorRequest(_id, bytes4(keccak256(_fulfillmentSignature))); + _sendOperatorRequestTo(_oracle, run, _wei); } function publicCancelRequest( @@ -54,11 +54,11 @@ contract ChainlinkClientTestHelper is ChainlinkClient { bytes4 _callbackFunctionId, uint256 _expiration ) public { - cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); + _cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); } function publicChainlinkToken() public view returns (address) { - return chainlinkTokenAddress(); + return _chainlinkTokenAddress(); } function publicFulfillChainlinkRequest(bytes32 _requestId, bytes32) public { @@ -66,7 +66,7 @@ contract ChainlinkClientTestHelper is ChainlinkClient { } function fulfillRequest(bytes32 _requestId, bytes32) public { - validateChainlinkCallback(_requestId); + _validateChainlinkCallback(_requestId); } function publicLINK(uint256 _amount) public { @@ -74,10 +74,10 @@ contract ChainlinkClientTestHelper is ChainlinkClient { } function publicOracleAddress() public view returns (address) { - return chainlinkOracleAddress(); + return _chainlinkOracleAddress(); } function publicAddExternalRequest(address _oracle, bytes32 _requestId) public { - addChainlinkExternalRequest(_oracle, _requestId); + _addChainlinkExternalRequest(_oracle, _requestId); } } diff --git a/contracts/src/v0.8/tests/ChainlinkTestHelper.sol b/contracts/src/v0.8/tests/ChainlinkTestHelper.sol index 1ca38f3038f..d42f30c374d 100644 --- a/contracts/src/v0.8/tests/ChainlinkTestHelper.sol +++ b/contracts/src/v0.8/tests/ChainlinkTestHelper.sol @@ -19,31 +19,31 @@ contract ChainlinkTestHelper { function setBuffer(bytes memory data) public { Chainlink.Request memory r2 = req; - r2.setBuffer(data); + r2._setBuffer(data); req = r2; } function add(string memory _key, string memory _value) public { Chainlink.Request memory r2 = req; - r2.add(_key, _value); + r2._add(_key, _value); req = r2; } function addBytes(string memory _key, bytes memory _value) public { Chainlink.Request memory r2 = req; - r2.addBytes(_key, _value); + r2._addBytes(_key, _value); req = r2; } function addInt(string memory _key, int256 _value) public { Chainlink.Request memory r2 = req; - r2.addInt(_key, _value); + r2._addInt(_key, _value); req = r2; } function addUint(string memory _key, uint256 _value) public { Chainlink.Request memory r2 = req; - r2.addUint(_key, _value); + r2._addUint(_key, _value); req = r2; } @@ -51,7 +51,7 @@ contract ChainlinkTestHelper { // string[] memory can be invoked from truffle tests. function addStringArray(string memory _key, string[] memory _values) public { Chainlink.Request memory r2 = req; - r2.addStringArray(_key, _values); + r2._addStringArray(_key, _values); req = r2; } } diff --git a/contracts/src/v0.8/dev/transmission/ERC-4337/Paymaster.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol similarity index 72% rename from contracts/src/v0.8/dev/transmission/ERC-4337/Paymaster.sol rename to contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol index 52d50d2e2c7..cd84bb6a0e0 100644 --- a/contracts/src/v0.8/dev/transmission/ERC-4337/Paymaster.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; -import "../../../vendor/entrypoint/interfaces/IPaymaster.sol"; -import "./SCALibrary.sol"; -import "../../../vendor/entrypoint/core/Helpers.sol"; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../../interfaces/AggregatorV3Interface.sol"; -import "./SCALibrary.sol"; -import "../../../shared/access/ConfirmedOwner.sol"; +import {IPaymaster} from "../../../vendor/entrypoint/interfaces/IPaymaster.sol"; +import {SCALibrary} from "./SCALibrary.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {AggregatorV3Interface} from "../../../interfaces/AggregatorV3Interface.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {UserOperation} from "../../../vendor/entrypoint/interfaces/UserOperation.sol"; +import {_packValidationData} from "../../../vendor/entrypoint/core/Helpers.sol"; /// @dev LINK token paymaster implementation. /// TODO: more documentation. @@ -28,8 +28,8 @@ contract Paymaster is IPaymaster, ConfirmedOwner { } Config public s_config; - mapping(bytes32 => bool) userOpHashMapping; - mapping(address => uint256) subscriptions; + mapping(bytes32 => bool) internal s_userOpHashMapping; + mapping(address => uint256) internal s_subscriptions; constructor( LinkTokenInterface linkToken, @@ -54,7 +54,7 @@ contract Paymaster is IPaymaster, ConfirmedOwner { } address subscription = abi.decode(_data, (address)); - subscriptions[subscription] += _amount; + s_subscriptions[subscription] += _amount; } function validatePaymasterUserOp( @@ -65,24 +65,24 @@ contract Paymaster is IPaymaster, ConfirmedOwner { if (msg.sender != i_entryPoint) { revert Unauthorized(msg.sender, i_entryPoint); } - if (userOpHashMapping[userOpHash]) { + if (s_userOpHashMapping[userOpHash]) { revert UserOperationAlreadyTried(userOpHash); } - uint256 extraCostJuels = handleExtraCostJuels(userOp); - uint256 costJuels = getCostJuels(maxCost) + extraCostJuels; - if (subscriptions[userOp.sender] < costJuels) { - revert InsufficientFunds(costJuels, subscriptions[userOp.sender]); + uint256 extraCostJuels = _handleExtraCostJuels(userOp); + uint256 costJuels = _getCostJuels(maxCost) + extraCostJuels; + if (s_subscriptions[userOp.sender] < costJuels) { + revert InsufficientFunds(costJuels, s_subscriptions[userOp.sender]); } - userOpHashMapping[userOpHash] = true; + s_userOpHashMapping[userOpHash] = true; return (abi.encode(userOp.sender, extraCostJuels), _packValidationData(false, 0, 0)); // success } /// @dev Calculates any extra LINK cost for the user operation, based on the funding type passed to the /// @dev paymaster. Handles funding the LINK token funding described in the user operation. /// TODO: add logic for subscription top-up. - function handleExtraCostJuels(UserOperation calldata userOp) internal returns (uint256 extraCost) { + function _handleExtraCostJuels(UserOperation calldata userOp) internal returns (uint256 extraCost) { if (userOp.paymasterAndData.length == 20) { return 0; // no extra data, stop here } @@ -111,14 +111,14 @@ contract Paymaster is IPaymaster, ConfirmedOwner { revert Unauthorized(msg.sender, i_entryPoint); } (address sender, uint256 extraCostJuels) = abi.decode(context, (address, uint256)); - subscriptions[sender] -= (getCostJuels(actualGasCost) + extraCostJuels); + s_subscriptions[sender] -= (_getCostJuels(actualGasCost) + extraCostJuels); } - function getCostJuels(uint256 costWei) internal view returns (uint256 costJuels) { - costJuels = (1e18 * costWei) / uint256(getFeedData()); + function _getCostJuels(uint256 costWei) internal view returns (uint256 costJuels) { + costJuels = (1e18 * costWei) / uint256(_getFeedData()); } - function getFeedData() internal view returns (int256) { + function _getFeedData() internal view returns (int256) { uint32 stalenessSeconds = s_config.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; diff --git a/contracts/src/v0.8/dev/transmission/ERC-4337/SCA.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol similarity index 85% rename from contracts/src/v0.8/dev/transmission/ERC-4337/SCA.sol rename to contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol index bf1ddf41af9..6a11eecfe00 100644 --- a/contracts/src/v0.8/dev/transmission/ERC-4337/SCA.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCA.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT -import "../../../vendor/entrypoint/interfaces/IAccount.sol"; -import "./SCALibrary.sol"; -import "../../../vendor/entrypoint/core/Helpers.sol"; - /// TODO: decide on a compiler version. Must not be dynamic, and must be > 0.8.12. pragma solidity 0.8.15; +import {IAccount} from "../../../vendor/entrypoint/interfaces/IAccount.sol"; +import {SCALibrary} from "./SCALibrary.sol"; +import {UserOperation} from "../../../vendor/entrypoint/interfaces/UserOperation.sol"; +import {_packValidationData} from "../../../vendor/entrypoint/core/Helpers.sol"; + /// @dev Smart Contract Account, a contract deployed for a single user and that allows /// @dev them to invoke meta-transactions. /// TODO: Consider making the Smart Contract Account upgradeable. @@ -39,9 +40,9 @@ contract SCA is IAccount { } // Verify signature on hash. - bytes32 fullHash = SCALibrary.getUserOpFullHash(userOpHash, address(this)); + bytes32 fullHash = SCALibrary._getUserOpFullHash(userOpHash, address(this)); bytes memory signature = userOp.signature; - if (SCALibrary.recoverSignature(signature, fullHash) != i_owner) { + if (SCALibrary._recoverSignature(signature, fullHash) != i_owner) { return _packValidationData(true, 0, 0); // signature error } s_nonce++; diff --git a/contracts/src/v0.8/dev/transmission/ERC-4337/SCALibrary.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol similarity index 85% rename from contracts/src/v0.8/dev/transmission/ERC-4337/SCALibrary.sol rename to contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol index 23c865c2e5d..47587e278f4 100644 --- a/contracts/src/v0.8/dev/transmission/ERC-4337/SCALibrary.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol @@ -19,7 +19,7 @@ library SCALibrary { uint256 topupAmount; } - function getUserOpFullHash(bytes32 userOpHash, address scaAddress) internal view returns (bytes32 fullHash) { + function _getUserOpFullHash(bytes32 userOpHash, address scaAddress) internal view returns (bytes32 fullHash) { bytes32 hashOfEncoding = keccak256(abi.encode(SCALibrary.TYPEHASH, userOpHash)); fullHash = keccak256( abi.encodePacked( @@ -33,7 +33,7 @@ library SCALibrary { ); } - function recoverSignature(bytes memory signature, bytes32 fullHash) internal pure returns (address) { + function _recoverSignature(bytes memory signature, bytes32 fullHash) internal pure returns (address) { bytes32 r; bytes32 s; assembly { diff --git a/contracts/src/v0.8/dev/transmission/ERC-4337/SmartContractAccountFactory.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol similarity index 100% rename from contracts/src/v0.8/dev/transmission/ERC-4337/SmartContractAccountFactory.sol rename to contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol diff --git a/contracts/src/v0.8/dev/transmission/testhelpers/Greeter.sol b/contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol similarity index 100% rename from contracts/src/v0.8/dev/transmission/testhelpers/Greeter.sol rename to contracts/src/v0.8/transmission/dev/testhelpers/Greeter.sol diff --git a/contracts/src/v0.8/dev/transmission/testhelpers/SmartContractAccountHelper.sol b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol similarity index 73% rename from contracts/src/v0.8/dev/transmission/testhelpers/SmartContractAccountHelper.sol rename to contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol index 108cd5477ac..c33df49d16b 100644 --- a/contracts/src/v0.8/dev/transmission/testhelpers/SmartContractAccountHelper.sol +++ b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol @@ -1,11 +1,12 @@ -import "../ERC-4337/SCA.sol"; -import "../ERC-4337/SmartContractAccountFactory.sol"; -import "../ERC-4337/SCALibrary.sol"; - +// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; +import {SCA} from "../ERC-4337/SCA.sol"; +import {SmartContractAccountFactory} from "../ERC-4337/SmartContractAccountFactory.sol"; +import {SCALibrary} from "../ERC-4337/SCALibrary.sol"; + library SmartContractAccountHelper { - bytes constant initailizeCode = type(SCA).creationCode; + bytes internal constant INITIALIZE_CODE = type(SCA).creationCode; function getFullEndTxEncoding( address endContract, @@ -20,14 +21,14 @@ library SmartContractAccountHelper { } function getFullHashForSigning(bytes32 userOpHash, address scaAddress) public view returns (bytes32) { - return SCALibrary.getUserOpFullHash(userOpHash, scaAddress); + return SCALibrary._getUserOpFullHash(userOpHash, scaAddress); } function getSCAInitCodeWithConstructor( address owner, address entryPoint ) public pure returns (bytes memory initCode) { - initCode = bytes.concat(initailizeCode, abi.encode(owner, entryPoint)); + initCode = bytes.concat(INITIALIZE_CODE, abi.encode(owner, entryPoint)); } function getInitCode( @@ -36,7 +37,7 @@ library SmartContractAccountHelper { address entryPoint ) external pure returns (bytes memory initCode) { bytes32 salt = bytes32(uint256(uint160(owner)) << 96); - bytes memory initializeCodeWithConstructor = bytes.concat(initailizeCode, abi.encode(owner, entryPoint)); + bytes memory initializeCodeWithConstructor = bytes.concat(INITIALIZE_CODE, abi.encode(owner, entryPoint)); initCode = bytes.concat( bytes20(address(factory)), abi.encodeWithSelector( @@ -54,7 +55,7 @@ library SmartContractAccountHelper { address factory ) external pure returns (address) { bytes32 salt = bytes32(uint256(uint160(owner)) << 96); - bytes memory initializeCodeWithConstructor = bytes.concat(initailizeCode, abi.encode(owner, entryPoint)); + bytes memory initializeCodeWithConstructor = bytes.concat(INITIALIZE_CODE, abi.encode(owner, entryPoint)); bytes32 initializeCodeHash = keccak256(initializeCodeWithConstructor); return address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(factory), salt, initializeCodeHash))))); } @@ -63,7 +64,7 @@ library SmartContractAccountHelper { address recipient, uint256 topupThreshold, uint256 topupAmount - ) external view returns (bytes memory) { + ) external pure returns (bytes memory) { SCALibrary.DirectFundingData memory data = SCALibrary.DirectFundingData({ recipient: recipient, topupThreshold: topupThreshold, diff --git a/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol b/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol index 1266b484b8b..1947379929f 100644 --- a/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol +++ b/contracts/src/v0.8/vendor/MockOVMCrossDomainMessenger.sol @@ -2,7 +2,7 @@ pragma solidity >=0.7.6 <0.9.0; -import "./openzeppelin-solidity/v4.7.0/contracts/utils/Address.sol"; +import "./openzeppelin-solidity/v4.8.0/contracts/utils/Address.sol"; /** * @title iOVM_CrossDomainMessenger diff --git a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol b/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol deleted file mode 100644 index ccd05445134..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/proxy/utils/Initializable.sol +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) - -pragma solidity ^0.8.2; - -import "../../utils/AddressUpgradeable.sol"; - -/** - * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed - * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an - * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer - * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. - * - * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be - * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in - * case an upgrade adds a module that needs to be initialized. - * - * For example: - * - * [.hljs-theme-light.nopadding] - * ``` - * contract MyToken is ERC20Upgradeable { - * function initialize() initializer public { - * __ERC20_init("MyToken", "MTK"); - * } - * } - * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { - * function initializeV2() reinitializer(2) public { - * __ERC20Permit_init("MyToken"); - * } - * } - * ``` - * - * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as - * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. - * - * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure - * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. - * - * [CAUTION] - * ==== - * Avoid leaving a contract uninitialized. - * - * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation - * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke - * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: - * - * [.hljs-theme-light.nopadding] - * ``` - * /// @custom:oz-upgrades-unsafe-allow constructor - * constructor() { - * _disableInitializers(); - * } - * ``` - * ==== - */ -abstract contract Initializable { - /** - * @dev Indicates that the contract has been initialized. - * @custom:oz-retyped-from bool - */ - uint8 private _initialized; - - /** - * @dev Indicates that the contract is in the process of being initialized. - */ - bool private _initializing; - - /** - * @dev Triggered when the contract has been initialized or reinitialized. - */ - event Initialized(uint8 version); - - /** - * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, - * `onlyInitializing` functions can be used to initialize parent contracts. - * - * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a - * constructor. - * - * Emits an {Initialized} event. - */ - modifier initializer() { - bool isTopLevelCall = !_initializing; - require( - (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), - "Initializable: contract is already initialized" - ); - _initialized = 1; - if (isTopLevelCall) { - _initializing = true; - } - _; - if (isTopLevelCall) { - _initializing = false; - emit Initialized(1); - } - } - - /** - * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the - * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be - * used to initialize parent contracts. - * - * A reinitializer may be used after the original initialization step. This is essential to configure modules that - * are added through upgrades and that require initialization. - * - * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` - * cannot be nested. If one is invoked in the context of another, execution will revert. - * - * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in - * a contract, executing them in the right order is up to the developer or operator. - * - * WARNING: setting the version to 255 will prevent any future reinitialization. - * - * Emits an {Initialized} event. - */ - modifier reinitializer(uint8 version) { - require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); - _initialized = version; - _initializing = true; - _; - _initializing = false; - emit Initialized(version); - } - - /** - * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the - * {initializer} and {reinitializer} modifiers, directly or indirectly. - */ - modifier onlyInitializing() { - require(_initializing, "Initializable: contract is not initializing"); - _; - } - - /** - * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. - * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized - * to any version. It is recommended to use this to lock implementation contracts that are designed to be called - * through proxies. - * - * Emits an {Initialized} event the first time it is successfully executed. - */ - function _disableInitializers() internal virtual { - require(!_initializing, "Initializable: contract is initializing"); - if (_initialized < type(uint8).max) { - _initialized = type(uint8).max; - emit Initialized(type(uint8).max); - } - } - - /** - * @dev Returns the highest version that has been initialized. See {reinitializer}. - */ - function _getInitializedVersion() internal view returns (uint8) { - return _initialized; - } - - /** - * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. - */ - function _isInitializing() internal view returns (bool) { - return _initializing; - } -} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol b/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol deleted file mode 100644 index 0315380ba44..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/security/PausableUpgradeable.sol +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) - -pragma solidity ^0.8.0; - -import "../utils/ContextUpgradeable.sol"; -import "../proxy/utils/Initializable.sol"; - -/** - * @dev Contract module which allows children to implement an emergency stop - * mechanism that can be triggered by an authorized account. - * - * This module is used through inheritance. It will make available the - * modifiers `whenNotPaused` and `whenPaused`, which can be applied to - * the functions of your contract. Note that they will not be pausable by - * simply including this module, only once the modifiers are put in place. - */ -abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { - /** - * @dev Emitted when the pause is triggered by `account`. - */ - event Paused(address account); - - /** - * @dev Emitted when the pause is lifted by `account`. - */ - event Unpaused(address account); - - bool private _paused; - - /** - * @dev Initializes the contract in unpaused state. - */ - function __Pausable_init() internal onlyInitializing { - __Pausable_init_unchained(); - } - - function __Pausable_init_unchained() internal onlyInitializing { - _paused = false; - } - - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenNotPaused() { - _requireNotPaused(); - _; - } - - /** - * @dev Modifier to make a function callable only when the contract is paused. - * - * Requirements: - * - * - The contract must be paused. - */ - modifier whenPaused() { - _requirePaused(); - _; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view virtual returns (bool) { - return _paused; - } - - /** - * @dev Throws if the contract is paused. - */ - function _requireNotPaused() internal view virtual { - require(!paused(), "Pausable: paused"); - } - - /** - * @dev Throws if the contract is not paused. - */ - function _requirePaused() internal view virtual { - require(paused(), "Pausable: not paused"); - } - - /** - * @dev Triggers stopped state. - * - * Requirements: - * - * - The contract must not be paused. - */ - function _pause() internal virtual whenNotPaused { - _paused = true; - emit Paused(_msgSender()); - } - - /** - * @dev Returns to normal state. - * - * Requirements: - * - * - The contract must be paused. - */ - function _unpause() internal virtual whenPaused { - _paused = false; - emit Unpaused(_msgSender()); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[49] private __gap; -} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/AddressUpgradeable.sol b/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/AddressUpgradeable.sol deleted file mode 100644 index 8f571c7f7d0..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/AddressUpgradeable.sol +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) - -pragma solidity ^0.8.1; - -/** - * @dev Collection of functions related to the address type - */ -library AddressUpgradeable { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - * - * [IMPORTANT] - * ==== - * You shouldn't rely on `isContract` to protect against flash loan attacks! - * - * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets - * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract - * constructor. - * ==== - */ - function isContract(address account) internal view returns (bool) { - // This method relies on extcodesize/address.code.length, which returns 0 - // for contracts in construction, since the code is only stored at the end - // of the constructor execution. - - return account.code.length > 0; - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - (bool success, ) = recipient.call{value: amount}(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain `call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value, - string memory errorMessage - ) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - (bool success, bytes memory returndata) = target.call{value: value}(data); - return verifyCallResultFromTarget(target, success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { - return functionStaticCall(target, data, "Address: low-level static call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall( - address target, - bytes memory data, - string memory errorMessage - ) internal view returns (bytes memory) { - (bool success, bytes memory returndata) = target.staticcall(data); - return verifyCallResultFromTarget(target, success, returndata, errorMessage); - } - - /** - * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling - * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. - * - * _Available since v4.8._ - */ - function verifyCallResultFromTarget( - address target, - bool success, - bytes memory returndata, - string memory errorMessage - ) internal view returns (bytes memory) { - if (success) { - if (returndata.length == 0) { - // only check isContract if the call was successful and the return data is empty - // otherwise we already know that it was a contract - require(isContract(target), "Address: call to non-contract"); - } - return returndata; - } else { - _revert(returndata, errorMessage); - } - } - - /** - * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the - * revert reason or using the provided one. - * - * _Available since v4.3._ - */ - function verifyCallResult( - bool success, - bytes memory returndata, - string memory errorMessage - ) internal pure returns (bytes memory) { - if (success) { - return returndata; - } else { - _revert(returndata, errorMessage); - } - } - - function _revert(bytes memory returndata, string memory errorMessage) private pure { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - /// @solidity memory-safe-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } -} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/ContextUpgradeable.sol b/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/ContextUpgradeable.sol deleted file mode 100644 index c9d1e3e12c5..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-contracts-upgradeable/v4.8.1/utils/ContextUpgradeable.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) - -pragma solidity ^0.8.0; -import "../proxy/utils/Initializable.sol"; - -/** - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract ContextUpgradeable is Initializable { - function __Context_init() internal onlyInitializing { - } - - function __Context_init_unchained() internal onlyInitializing { - } - function _msgSender() internal view virtual returns (address) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes calldata) { - return msg.data; - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[50] private __gap; -} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol deleted file mode 100644 index bdd118432f0..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/security/Pausable.sol +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) - -pragma solidity ^0.8.0; - -import "../utils/Context.sol"; - -/** - * @dev Contract module which allows children to implement an emergency stop - * mechanism that can be triggered by an authorized account. - * - * This module is used through inheritance. It will make available the - * modifiers `whenNotPaused` and `whenPaused`, which can be applied to - * the functions of your contract. Note that they will not be pausable by - * simply including this module, only once the modifiers are put in place. - */ -abstract contract Pausable is Context { - /** - * @dev Emitted when the pause is triggered by `account`. - */ - event Paused(address account); - - /** - * @dev Emitted when the pause is lifted by `account`. - */ - event Unpaused(address account); - - bool private _paused; - - /** - * @dev Initializes the contract in unpaused state. - */ - constructor() { - _paused = false; - } - - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenNotPaused() { - _requireNotPaused(); - _; - } - - /** - * @dev Modifier to make a function callable only when the contract is paused. - * - * Requirements: - * - * - The contract must be paused. - */ - modifier whenPaused() { - _requirePaused(); - _; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view virtual returns (bool) { - return _paused; - } - - /** - * @dev Throws if the contract is paused. - */ - function _requireNotPaused() internal view virtual { - require(!paused(), "Pausable: paused"); - } - - /** - * @dev Throws if the contract is not paused. - */ - function _requirePaused() internal view virtual { - require(paused(), "Pausable: not paused"); - } - - /** - * @dev Triggers stopped state. - * - * Requirements: - * - * - The contract must not be paused. - */ - function _pause() internal virtual whenNotPaused { - _paused = true; - emit Paused(_msgSender()); - } - - /** - * @dev Returns to normal state. - * - * Requirements: - * - * - The contract must be paused. - */ - function _unpause() internal virtual whenPaused { - _paused = false; - emit Unpaused(_msgSender()); - } -} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol deleted file mode 100644 index b816bfed086..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/IERC20.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) - -pragma solidity ^0.8.0; - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); - - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller's account to `to`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address to, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `from` to `to` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom( - address from, - address to, - uint256 amount - ) external returns (bool); -} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/extensions/IERC20Permit.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/extensions/IERC20Permit.sol deleted file mode 100644 index bb43e53b6c3..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/extensions/IERC20Permit.sol +++ /dev/null @@ -1,60 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) - -pragma solidity ^0.8.0; - -/** - * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in - * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. - * - * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by - * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't - * need to send a transaction, and thus is not required to hold Ether at all. - */ -interface IERC20Permit { - /** - * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, - * given ``owner``'s signed approval. - * - * IMPORTANT: The same issues {IERC20-approve} has related to transaction - * ordering also apply here. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `deadline` must be a timestamp in the future. - * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` - * over the EIP712-formatted function arguments. - * - the signature must use ``owner``'s current nonce (see {nonces}). - * - * For more information on the signature format, see the - * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP - * section]. - */ - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - /** - * @dev Returns the current nonce for `owner`. This value must be - * included whenever a signature is generated for {permit}. - * - * Every successful call to {permit} increases ``owner``'s nonce by one. This - * prevents a signature from being used multiple times. - */ - function nonces(address owner) external view returns (uint256); - - /** - * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. - */ - // solhint-disable-next-line func-name-mixedcase - function DOMAIN_SEPARATOR() external view returns (bytes32); -} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/utils/SafeERC20.sol deleted file mode 100644 index ed37e941ab0..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/token/ERC20/utils/SafeERC20.sol +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) - -pragma solidity ^0.8.0; - -import "../IERC20.sol"; -import "../extensions/IERC20Permit.sol"; -import "../../../utils/Address.sol"; - -/** - * @title SafeERC20 - * @dev Wrappers around ERC20 operations that throw on failure (when the token - * contract returns false). Tokens that return no value (and instead revert or - * throw on failure) are also supported, non-reverting calls are assumed to be - * successful. - * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, - * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. - */ -library SafeERC20 { - using Address for address; - - function safeTransfer( - IERC20 token, - address to, - uint256 value - ) internal { - _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); - } - - function safeTransferFrom( - IERC20 token, - address from, - address to, - uint256 value - ) internal { - _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); - } - - /** - * @dev Deprecated. This function has issues similar to the ones found in - * {IERC20-approve}, and its usage is discouraged. - * - * Whenever possible, use {safeIncreaseAllowance} and - * {safeDecreaseAllowance} instead. - */ - function safeApprove( - IERC20 token, - address spender, - uint256 value - ) internal { - // safeApprove should only be called when setting an initial allowance, - // or when resetting it to zero. To increase and decrease it, use - // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' - require( - (value == 0) || (token.allowance(address(this), spender) == 0), - "SafeERC20: approve from non-zero to non-zero allowance" - ); - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); - } - - function safeIncreaseAllowance( - IERC20 token, - address spender, - uint256 value - ) internal { - uint256 newAllowance = token.allowance(address(this), spender) + value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); - } - - function safeDecreaseAllowance( - IERC20 token, - address spender, - uint256 value - ) internal { - unchecked { - uint256 oldAllowance = token.allowance(address(this), spender); - require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); - uint256 newAllowance = oldAllowance - value; - _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); - } - } - - function safePermit( - IERC20Permit token, - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) internal { - uint256 nonceBefore = token.nonces(owner); - token.permit(owner, spender, value, deadline, v, r, s); - uint256 nonceAfter = token.nonces(owner); - require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); - } - - /** - * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement - * on the return value: the return value is optional (but if data is returned, it must not be false). - * @param token The token targeted by the call. - * @param data The call data (encoded using abi.encode or one of its variants). - */ - function _callOptionalReturn(IERC20 token, bytes memory data) private { - // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since - // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that - // the target address contains contract code and also asserts for success in the low-level call. - - bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); - if (returndata.length > 0) { - // Return data is optional - require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); - } - } -} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Address.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Address.sol deleted file mode 100644 index 600f019b399..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Address.sol +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) - -pragma solidity ^0.8.1; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - * - * [IMPORTANT] - * ==== - * You shouldn't rely on `isContract` to protect against flash loan attacks! - * - * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets - * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract - * constructor. - * ==== - */ - function isContract(address account) internal view returns (bool) { - // This method relies on extcodesize/address.code.length, which returns 0 - // for contracts in construction, since the code is only stored at the end - // of the constructor execution. - - return account.code.length > 0; - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - (bool success, ) = recipient.call{value: amount}(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain `call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value - ) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue( - address target, - bytes memory data, - uint256 value, - string memory errorMessage - ) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - (bool success, bytes memory returndata) = target.call{value: value}(data); - return verifyCallResultFromTarget(target, success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { - return functionStaticCall(target, data, "Address: low-level static call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a static call. - * - * _Available since v3.3._ - */ - function functionStaticCall( - address target, - bytes memory data, - string memory errorMessage - ) internal view returns (bytes memory) { - (bool success, bytes memory returndata) = target.staticcall(data); - return verifyCallResultFromTarget(target, success, returndata, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { - return functionDelegateCall(target, data, "Address: low-level delegate call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], - * but performing a delegate call. - * - * _Available since v3.4._ - */ - function functionDelegateCall( - address target, - bytes memory data, - string memory errorMessage - ) internal returns (bytes memory) { - (bool success, bytes memory returndata) = target.delegatecall(data); - return verifyCallResultFromTarget(target, success, returndata, errorMessage); - } - - /** - * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling - * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. - * - * _Available since v4.8._ - */ - function verifyCallResultFromTarget( - address target, - bool success, - bytes memory returndata, - string memory errorMessage - ) internal view returns (bytes memory) { - if (success) { - if (returndata.length == 0) { - // only check isContract if the call was successful and the return data is empty - // otherwise we already know that it was a contract - require(isContract(target), "Address: call to non-contract"); - } - return returndata; - } else { - _revert(returndata, errorMessage); - } - } - - /** - * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the - * revert reason or using the provided one. - * - * _Available since v4.3._ - */ - function verifyCallResult( - bool success, - bytes memory returndata, - string memory errorMessage - ) internal pure returns (bytes memory) { - if (success) { - return returndata; - } else { - _revert(returndata, errorMessage); - } - } - - function _revert(bytes memory returndata, string memory errorMessage) private pure { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - /// @solidity memory-safe-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } -} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Context.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Context.sol deleted file mode 100644 index f304065b460..00000000000 --- a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.7.0/contracts/utils/Context.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) - -pragma solidity ^0.8.0; - -/** - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract Context { - function _msgSender() internal view virtual returns (address) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes calldata) { - return msg.data; - } -} diff --git a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol index c6c3a888289..e55616924cd 100644 --- a/contracts/src/v0.8/vrf/BatchBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/BatchBlockhashStore.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity 0.8.6; -import "../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; /** * @title BatchBlockhashStore @@ -11,6 +12,7 @@ import "../ChainSpecificUtil.sol"; * in times of high network congestion. */ contract BatchBlockhashStore { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i BlockhashStore public immutable BHS; constructor(address blockhashStoreAddr) { @@ -27,7 +29,7 @@ contract BatchBlockhashStore { for (uint256 i = 0; i < blockNumbers.length; i++) { // skip the block if it's not storeable, the caller will have to check // after the transaction is mined to see if the blockhash was truly stored. - if (!storeableBlock(blockNumbers[i])) { + if (!_storeableBlock(blockNumbers[i])) { continue; } BHS.store(blockNumbers[i]); @@ -40,6 +42,7 @@ contract BatchBlockhashStore { * @param headers the rlp-encoded block headers of blockNumbers[i] + 1. */ function storeVerifyHeader(uint256[] memory blockNumbers, bytes[] memory headers) public { + // solhint-disable-next-line custom-errors require(blockNumbers.length == headers.length, "input array arg lengths mismatch"); for (uint256 i = 0; i < blockNumbers.length; i++) { BHS.storeVerifyHeader(blockNumbers[i], headers[i]); @@ -70,9 +73,10 @@ contract BatchBlockhashStore { * using the blockhash() instruction. * @param blockNumber the block number to check if it's storeable with blockhash() */ - function storeableBlock(uint256 blockNumber) private view returns (bool) { + function _storeableBlock(uint256 blockNumber) private view returns (bool) { // handle edge case on simulated chains which possibly have < 256 blocks total. - return ChainSpecificUtil.getBlockNumber() <= 256 ? true : blockNumber >= (ChainSpecificUtil.getBlockNumber() - 256); + return + ChainSpecificUtil._getBlockNumber() <= 256 ? true : blockNumber >= (ChainSpecificUtil._getBlockNumber() - 256); } } diff --git a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol index 83f0a78359d..b35df41d1e3 100644 --- a/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/BatchVRFCoordinatorV2.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity 0.8.6; -import "./VRFTypes.sol"; +import {VRFTypes} from "./VRFTypes.sol"; /** * @title BatchVRFCoordinatorV2 @@ -9,6 +10,7 @@ import "./VRFTypes.sol"; * provided VRFCoordinatorV2 contract efficiently in a single transaction. */ contract BatchVRFCoordinatorV2 { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i VRFCoordinatorV2 public immutable COORDINATOR; event ErrorReturned(uint256 indexed requestId, string reason); @@ -24,15 +26,16 @@ contract BatchVRFCoordinatorV2 { * @param rcs the request commitments corresponding to the randomness proofs. */ function fulfillRandomWords(VRFTypes.Proof[] memory proofs, VRFTypes.RequestCommitment[] memory rcs) external { + // solhint-disable-next-line custom-errors require(proofs.length == rcs.length, "input array arg lengths mismatch"); for (uint256 i = 0; i < proofs.length; i++) { try COORDINATOR.fulfillRandomWords(proofs[i], rcs[i]) returns (uint96 /* payment */) { continue; } catch Error(string memory reason) { - uint256 requestId = getRequestIdFromProof(proofs[i]); + uint256 requestId = _getRequestIdFromProof(proofs[i]); emit ErrorReturned(requestId, reason); } catch (bytes memory lowLevelData) { - uint256 requestId = getRequestIdFromProof(proofs[i]); + uint256 requestId = _getRequestIdFromProof(proofs[i]); emit RawErrorReturned(requestId, lowLevelData); } } @@ -42,7 +45,7 @@ contract BatchVRFCoordinatorV2 { * @notice Returns the proving key hash associated with this public key. * @param publicKey the key to return the hash of. */ - function hashOfKey(uint256[2] memory publicKey) internal pure returns (bytes32) { + function _hashOfKey(uint256[2] memory publicKey) internal pure returns (bytes32) { return keccak256(abi.encode(publicKey)); } @@ -50,8 +53,8 @@ contract BatchVRFCoordinatorV2 { * @notice Returns the request ID of the request associated with the given proof. * @param proof the VRF proof provided by the VRF oracle. */ - function getRequestIdFromProof(VRFTypes.Proof memory proof) internal pure returns (uint256) { - bytes32 keyHash = hashOfKey(proof.pk); + function _getRequestIdFromProof(VRFTypes.Proof memory proof) internal pure returns (uint256) { + bytes32 keyHash = _hashOfKey(proof.pk); return uint256(keccak256(abi.encode(keyHash, proof.seed))); } } diff --git a/contracts/src/v0.8/KeepersVRFConsumer.sol b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol similarity index 87% rename from contracts/src/v0.8/KeepersVRFConsumer.sol rename to contracts/src/v0.8/vrf/KeepersVRFConsumer.sol index 21fd26290a4..a18c6e03798 100644 --- a/contracts/src/v0.8/KeepersVRFConsumer.sol +++ b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./automation/KeeperCompatible.sol"; -import "./vrf/VRFConsumerBaseV2.sol"; -import "./interfaces/VRFCoordinatorV2Interface.sol"; +import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "../automation/interfaces/AutomationCompatibleInterface.sol"; +import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; + +// solhint-disable chainlink-solidity/prefix-immutable-variables-with-i /** * @title KeepersVRFConsumer @@ -73,7 +75,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { if ((block.timestamp - s_lastTimeStamp) > UPKEEP_INTERVAL) { s_lastTimeStamp = block.timestamp; - requestRandomWords(); + _requestRandomWords(); } } @@ -82,9 +84,11 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { * @param requestId the VRF V2 request ID, provided at request time. * @param randomWords the randomness provided by Chainlink VRF. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { // Check that the request exists. If not, revert. RequestRecord memory record = s_requests[requestId]; + // solhint-disable-next-line custom-errors require(record.requestId == requestId, "request ID not found in map"); // Update the randomness in the record, and increment the response counter. @@ -95,7 +99,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { /** * @notice Requests random words from Chainlink VRF. */ - function requestRandomWords() internal { + function _requestRandomWords() internal { uint256 requestId = COORDINATOR.requestRandomWords( KEY_HASH, SUBSCRIPTION_ID, diff --git a/contracts/src/v0.8/vrf/VRF.sol b/contracts/src/v0.8/vrf/VRF.sol index a6c35c79043..a19fc39ec3e 100644 --- a/contracts/src/v0.8/vrf/VRF.sol +++ b/contracts/src/v0.8/vrf/VRF.sol @@ -17,7 +17,7 @@ pragma solidity ^0.8.0; * **************************************************************************** * @dev USAGE - * @dev The main entry point is randomValueFromVRFProof. See its docstring. + * @dev The main entry point is _randomValueFromVRFProof. See its docstring. * **************************************************************************** * @dev PURPOSE @@ -57,18 +57,18 @@ pragma solidity ^0.8.0; * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.5 * @dev For curve-point multiplication, it's much cheaper to abuse ECRECOVER - * @dev - hashToCurve recursively hashes until it finds a curve x-ordinate. On + * @dev - _hashToCurve recursively hashes until it finds a curve x-ordinate. On * @dev the EVM, this is slightly more efficient than the recommendation in * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.1.1 * @dev step 5, to concatenate with a nonce then hash, and rehash with the * @dev nonce updated until a valid x-ordinate is found. - * @dev - hashToCurve does not include a cipher version string or the byte 0x1 + * @dev - _hashToCurve does not include a cipher version string or the byte 0x1 * @dev in the hash message, as recommended in step 5.B of the draft * @dev standard. They are unnecessary here because no variation in the * @dev cipher suite is allowed. - * @dev - Similarly, the hash input in scalarFromCurvePoints does not include a + * @dev - Similarly, the hash input in _scalarFromCurvePoints does not include a * @dev commitment to the cipher suite, either, which differs from step 2 of * @dev https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.3 * @dev . Also, the hash input is the concatenation of the uncompressed @@ -88,7 +88,7 @@ pragma solidity ^0.8.0; * @dev Full uniqueness: For any seed and valid VRF public key, there is * @dev exactly one VRF output which can be proved to come from that seed, in - * @dev the sense that the proof will pass verifyVRFProof. + * @dev the sense that the proof will pass _verifyVRFProof. * @dev Full collision resistance: It's cryptographically infeasible to find * @dev two seeds with same VRF output from a fixed, valid VRF key @@ -110,13 +110,13 @@ pragma solidity ^0.8.0; * @dev OTHER SECURITY CONSIDERATIONS * * @dev The seed input to the VRF could in principle force an arbitrary amount - * @dev of work in hashToCurve, by requiring extra rounds of hashing and + * @dev of work in _hashToCurve, by requiring extra rounds of hashing and * @dev checking whether that's yielded the x ordinate of a secp256k1 point. * @dev However, under the Random Oracle Model the probability of choosing a - * @dev point which forces n extra rounds in hashToCurve is 2⁻ⁿ. The base cost - * @dev for calling hashToCurve is about 25,000 gas, and each round of checking + * @dev point which forces n extra rounds in _hashToCurve is 2⁻ⁿ. The base cost + * @dev for calling _hashToCurve is about 25,000 gas, and each round of checking * @dev for a valid x ordinate costs about 15,555 gas, so to find a seed for - * @dev which hashToCurve would cost more than 2,017,000 gas, one would have to + * @dev which _hashToCurve would cost more than 2,017,000 gas, one would have to * @dev try, in expectation, about 2¹²⁸ seeds, which is infeasible for any * @dev foreseeable computational resources. (25,000 + 128 * 15,555 < 2,017,000.) @@ -125,10 +125,10 @@ pragma solidity ^0.8.0; * @dev operation of this contract by choosing an adverse seed. * @dev (See TestMeasureHashToCurveGasCost for verification of the gas cost for - * @dev hashToCurve.) + * @dev _hashToCurve.) - * @dev It may be possible to make a secure constant-time hashToCurve function. - * @dev See notes in hashToCurve docstring. + * @dev It may be possible to make a secure constant-time _hashToCurve function. + * @dev See notes in _hashToCurve docstring. */ contract VRF { // See https://www.secg.org/sec2-v2.pdf, section 2.4.1, for these constants. @@ -142,7 +142,7 @@ contract VRF { // (base^exponent) % FIELD_SIZE // Cribbed from https://medium.com/@rbkhmrcr/precompiles-solidity-e5d29bd428c4 - function bigModExp(uint256 base, uint256 exponent) internal view returns (uint256 exponentiation) { + function _bigModExp(uint256 base, uint256 exponent) internal view returns (uint256 exponentiation) { uint256 callResult; uint256[6] memory bigModExpContractInputs; bigModExpContractInputs[0] = WORD_LENGTH_BYTES; // Length of base @@ -153,7 +153,6 @@ contract VRF { bigModExpContractInputs[5] = FIELD_SIZE; uint256[1] memory output; assembly { - // solhint-disable-line no-inline-assembly callResult := staticcall( not(0), // Gas cost: no limit 0x05, // Bigmodexp contract address @@ -164,6 +163,7 @@ contract VRF { ) } if (callResult == 0) { + // solhint-disable-next-line custom-errors revert("bigModExp failure!"); } return output[0]; @@ -174,28 +174,30 @@ contract VRF { uint256 private constant SQRT_POWER = (FIELD_SIZE + 1) >> 2; // Computes a s.t. a^2 = x in the field. Assumes a exists - function squareRoot(uint256 x) internal view returns (uint256) { - return bigModExp(x, SQRT_POWER); + function _squareRoot(uint256 x) internal view returns (uint256) { + return _bigModExp(x, SQRT_POWER); } // The value of y^2 given that (x,y) is on secp256k1. - function ySquared(uint256 x) internal pure returns (uint256) { + function _ySquared(uint256 x) internal pure returns (uint256) { // Curve is y^2=x^3+7. See section 2.4.1 of https://www.secg.org/sec2-v2.pdf uint256 xCubed = mulmod(x, mulmod(x, x, FIELD_SIZE), FIELD_SIZE); return addmod(xCubed, 7, FIELD_SIZE); } // True iff p is on secp256k1 - function isOnCurve(uint256[2] memory p) internal pure returns (bool) { + function _isOnCurve(uint256[2] memory p) internal pure returns (bool) { // Section 2.3.6. in https://www.secg.org/sec1-v2.pdf // requires each ordinate to be in [0, ..., FIELD_SIZE-1] + // solhint-disable-next-line custom-errors require(p[0] < FIELD_SIZE, "invalid x-ordinate"); + // solhint-disable-next-line custom-errors require(p[1] < FIELD_SIZE, "invalid y-ordinate"); - return ySquared(p[0]) == mulmod(p[1], p[1], FIELD_SIZE); + return _ySquared(p[0]) == mulmod(p[1], p[1], FIELD_SIZE); } // Hash x uniformly into {0, ..., FIELD_SIZE-1}. - function fieldHash(bytes memory b) internal pure returns (uint256 x_) { + function _fieldHash(bytes memory b) internal pure returns (uint256 x_) { x_ = uint256(keccak256(b)); // Rejecting if x >= FIELD_SIZE corresponds to step 2.1 in section 2.3.4 of // http://www.secg.org/sec1-v2.pdf , which is part of the definition of @@ -211,10 +213,10 @@ contract VRF { // step 5.C, which references arbitrary_string_to_point, defined in // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.5 as // returning the point with given x ordinate, and even y ordinate. - function newCandidateSecp256k1Point(bytes memory b) internal view returns (uint256[2] memory p) { + function _newCandidateSecp256k1Point(bytes memory b) internal view returns (uint256[2] memory p) { unchecked { - p[0] = fieldHash(b); - p[1] = squareRoot(ySquared(p[0])); + p[0] = _fieldHash(b); + p[1] = _squareRoot(_ySquared(p[0])); if (p[1] % 2 == 1) { // Note that 0 <= p[1] < FIELD_SIZE // so this cannot wrap, we use unchecked to save gas. @@ -223,7 +225,7 @@ contract VRF { } } - // Domain-separation tag for initial hash in hashToCurve. Corresponds to + // Domain-separation tag for initial hash in _hashToCurve. Corresponds to // vrf.go/hashToCurveHashPrefix uint256 internal constant HASH_TO_CURVE_HASH_PREFIX = 1; @@ -241,10 +243,10 @@ contract VRF { // // This would greatly simplify the analysis in "OTHER SECURITY CONSIDERATIONS" // https://www.pivotaltracker.com/story/show/171120900 - function hashToCurve(uint256[2] memory pk, uint256 input) internal view returns (uint256[2] memory rv) { - rv = newCandidateSecp256k1Point(abi.encodePacked(HASH_TO_CURVE_HASH_PREFIX, pk, input)); - while (!isOnCurve(rv)) { - rv = newCandidateSecp256k1Point(abi.encodePacked(rv[0])); + function _hashToCurve(uint256[2] memory pk, uint256 input) internal view returns (uint256[2] memory rv) { + rv = _newCandidateSecp256k1Point(abi.encodePacked(HASH_TO_CURVE_HASH_PREFIX, pk, input)); + while (!_isOnCurve(rv)) { + rv = _newCandidateSecp256k1Point(abi.encodePacked(rv[0])); } } @@ -258,11 +260,12 @@ contract VRF { * @param product: secp256k1 expected to be multiplier * multiplicand * @return verifies true iff product==scalar*multiplicand, with cryptographically high probability */ - function ecmulVerify( + function _ecmulVerify( uint256[2] memory multiplicand, uint256 scalar, uint256[2] memory product ) internal pure returns (bool verifies) { + // solhint-disable-next-line custom-errors require(scalar != 0, "zero scalar"); // Rules out an ecrecover failure case uint256 x = multiplicand[0]; // x ordinate of multiplicand uint8 v = multiplicand[1] % 2 == 0 ? 27 : 28; // parity of y ordinate @@ -278,7 +281,7 @@ contract VRF { } // Returns x1/z1-x2/z2=(x1z2-x2z1)/(z1z2) in projective coordinates on P¹(𝔽ₙ) - function projectiveSub( + function _projectiveSub( uint256 x1, uint256 z1, uint256 x2, @@ -294,7 +297,7 @@ contract VRF { } // Returns x1/z1*x2/z2=(x1x2)/(z1z2), in projective coordinates on P¹(𝔽ₙ) - function projectiveMul( + function _projectiveMul( uint256 x1, uint256 z1, uint256 x2, @@ -309,7 +312,7 @@ contract VRF { @dev Using projective coordinates avoids costly divisions @dev To use this with p and q in affine coordinates, call - @dev projectiveECAdd(px, py, qx, qy). This will return + @dev _projectiveECAdd(px, py, qx, qy). This will return @dev the addition of (px, py, 1) and (qx, qy, 1), in the @dev secp256k1 group. @@ -319,7 +322,7 @@ contract VRF { @dev This function assumes [px,py,1],[qx,qy,1] are valid projective coordinates of secp256k1 points. That is safe in this contract, - because this method is only used by linearCombination, which checks + because this method is only used by _linearCombination, which checks points are on the curve via ecrecover. ************************************************************************** @param px The first affine coordinate of the first summand @@ -335,7 +338,7 @@ contract VRF { @return sy @return sz */ - function projectiveECAdd( + function _projectiveECAdd( uint256 px, uint256 py, uint256 qx, @@ -346,11 +349,11 @@ contract VRF { // "Guide to Elliptic Curve Cryptography" by Hankerson, Menezes and Vanstone // We take the equations there for (sx,sy), and homogenize them to // projective coordinates. That way, no inverses are required, here, and we - // only need the one inverse in affineECAdd. + // only need the one inverse in _affineECAdd. // We only need the "point addition" equations from Hankerson et al. Can // skip the "point doubling" equations because p1 == p2 is cryptographically - // impossible, and required not to be the case in linearCombination. + // impossible, and required not to be the case in _linearCombination. // Add extra "projective coordinate" to the two points (uint256 z1, uint256 z2) = (1, 1); @@ -362,15 +365,15 @@ contract VRF { uint256 dx; // Accumulates denominator from sx calculation // sx=((qy-py)/(qx-px))^2-px-qx - (sx, dx) = projectiveMul(lx, lz, lx, lz); // ((qy-py)/(qx-px))^2 - (sx, dx) = projectiveSub(sx, dx, px, z1); // ((qy-py)/(qx-px))^2-px - (sx, dx) = projectiveSub(sx, dx, qx, z2); // ((qy-py)/(qx-px))^2-px-qx + (sx, dx) = _projectiveMul(lx, lz, lx, lz); // ((qy-py)/(qx-px))^2 + (sx, dx) = _projectiveSub(sx, dx, px, z1); // ((qy-py)/(qx-px))^2-px + (sx, dx) = _projectiveSub(sx, dx, qx, z2); // ((qy-py)/(qx-px))^2-px-qx uint256 dy; // Accumulates denominator from sy calculation // sy=((qy-py)/(qx-px))(px-sx)-py - (sy, dy) = projectiveSub(px, z1, sx, dx); // px-sx - (sy, dy) = projectiveMul(sy, dy, lx, lz); // ((qy-py)/(qx-px))(px-sx) - (sy, dy) = projectiveSub(sy, dy, py, z1); // ((qy-py)/(qx-px))(px-sx)-py + (sy, dy) = _projectiveSub(px, z1, sx, dx); // px-sx + (sy, dy) = _projectiveMul(sy, dy, lx, lz); // ((qy-py)/(qx-px))(px-sx) + (sy, dy) = _projectiveSub(sy, dy, py, z1); // ((qy-py)/(qx-px))(px-sx)-py if (dx != dy) { // Cross-multiply to put everything over a common denominator @@ -386,12 +389,12 @@ contract VRF { // p1+p2, as affine points on secp256k1. // - // invZ must be the inverse of the z returned by projectiveECAdd(p1, p2). + // invZ must be the inverse of the z returned by _projectiveECAdd(p1, p2). // It is computed off-chain to save gas. // - // p1 and p2 must be distinct, because projectiveECAdd doesn't handle + // p1 and p2 must be distinct, because _projectiveECAdd doesn't handle // point doubling. - function affineECAdd( + function _affineECAdd( uint256[2] memory p1, uint256[2] memory p2, uint256 invZ @@ -399,7 +402,8 @@ contract VRF { uint256 x; uint256 y; uint256 z; - (x, y, z) = projectiveECAdd(p1[0], p1[1], p2[0], p2[1]); + (x, y, z) = _projectiveECAdd(p1[0], p1[1], p2[0], p2[1]); + // solhint-disable-next-line custom-errors require(mulmod(z, invZ, FIELD_SIZE) == 1, "invZ must be inverse of z"); // Clear the z ordinate of the projective representation by dividing through // by it, to obtain the affine representation @@ -408,7 +412,7 @@ contract VRF { // True iff address(c*p+s*g) == lcWitness, where g is generator. (With // cryptographically high probability.) - function verifyLinearCombinationWithGenerator( + function _verifyLinearCombinationWithGenerator( uint256 c, uint256[2] memory p, uint256 s, @@ -416,6 +420,7 @@ contract VRF { ) internal pure returns (bool) { // Rule out ecrecover failure modes which return address 0. unchecked { + // solhint-disable-next-line custom-errors require(lcWitness != address(0), "bad witness"); uint8 v = (p[1] % 2 == 0) ? 27 : 28; // parity of y-ordinate of p // Note this cannot wrap (X - Y % X), but we use unchecked to save @@ -439,8 +444,8 @@ contract VRF { // (cryptographically impossible) case that a prover accidentally derives // a proof with equal c*p1 and s*p2, they should retry with a different // proof nonce.) Assumes that all points are on secp256k1 - // (which is checked in verifyVRFProof below.) - function linearCombination( + // (which is checked in _verifyVRFProof below.) + function _linearCombination( uint256 c, uint256[2] memory p1, uint256[2] memory cp1Witness, @@ -451,18 +456,21 @@ contract VRF { ) internal pure returns (uint256[2] memory) { unchecked { // Note we are relying on the wrap around here + // solhint-disable-next-line custom-errors require((cp1Witness[0] % FIELD_SIZE) != (sp2Witness[0] % FIELD_SIZE), "points in sum must be distinct"); - require(ecmulVerify(p1, c, cp1Witness), "First mul check failed"); - require(ecmulVerify(p2, s, sp2Witness), "Second mul check failed"); - return affineECAdd(cp1Witness, sp2Witness, zInv); + // solhint-disable-next-line custom-errors + require(_ecmulVerify(p1, c, cp1Witness), "First mul check failed"); + // solhint-disable-next-line custom-errors + require(_ecmulVerify(p2, s, sp2Witness), "Second mul check failed"); + return _affineECAdd(cp1Witness, sp2Witness, zInv); } } - // Domain-separation tag for the hash taken in scalarFromCurvePoints. + // Domain-separation tag for the hash taken in _scalarFromCurvePoints. // Corresponds to scalarFromCurveHashPrefix in vrf.go uint256 internal constant SCALAR_FROM_CURVE_POINTS_HASH_PREFIX = 2; - // Pseudo-random number from inputs. Matches vrf.go/scalarFromCurvePoints, and + // Pseudo-random number from inputs. Matches vrf.go/_scalarFromCurvePoints, and // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-05#section-5.4.3 // The draft calls (in step 7, via the definition of string_to_int, in // https://datatracker.ietf.org/doc/html/rfc8017#section-4.2 ) for taking the @@ -473,7 +481,7 @@ contract VRF { // using the compressed representation of the points, if we collated the y // parities into a single bytes32. // https://www.pivotaltracker.com/story/show/171120588 - function scalarFromCurvePoints( + function _scalarFromCurvePoints( uint256[2] memory hash, uint256[2] memory pk, uint256[2] memory gamma, @@ -485,14 +493,14 @@ contract VRF { // True if (gamma, c, s) is a correctly constructed randomness proof from pk // and seed. zInv must be the inverse of the third ordinate from - // projectiveECAdd applied to cGammaWitness and sHashWitness. Corresponds to + // _projectiveECAdd applied to cGammaWitness and sHashWitness. Corresponds to // section 5.3 of the IETF draft. // // TODO(alx): Since I'm only using pk in the ecrecover call, I could only pass // the x ordinate, and the parity of the y ordinate in the top bit of uWitness // (which I could make a uint256 without using any extra space.) Would save // about 2000 gas. https://www.pivotaltracker.com/story/show/170828567 - function verifyVRFProof( + function _verifyVRFProof( uint256[2] memory pk, uint256[2] memory gamma, uint256 c, @@ -504,22 +512,28 @@ contract VRF { uint256 zInv ) internal view { unchecked { - require(isOnCurve(pk), "public key is not on curve"); - require(isOnCurve(gamma), "gamma is not on curve"); - require(isOnCurve(cGammaWitness), "cGammaWitness is not on curve"); - require(isOnCurve(sHashWitness), "sHashWitness is not on curve"); + // solhint-disable-next-line custom-errors + require(_isOnCurve(pk), "public key is not on curve"); + // solhint-disable-next-line custom-errors + require(_isOnCurve(gamma), "gamma is not on curve"); + // solhint-disable-next-line custom-errors + require(_isOnCurve(cGammaWitness), "cGammaWitness is not on curve"); + // solhint-disable-next-line custom-errors + require(_isOnCurve(sHashWitness), "sHashWitness is not on curve"); // Step 5. of IETF draft section 5.3 (pk corresponds to 5.3's Y, and here // we use the address of u instead of u itself. Also, here we add the // terms instead of taking the difference, and in the proof construction in // vrf.GenerateProof, we correspondingly take the difference instead of // taking the sum as they do in step 7 of section 5.1.) - require(verifyLinearCombinationWithGenerator(c, pk, s, uWitness), "addr(c*pk+s*g)!=_uWitness"); + // solhint-disable-next-line custom-errors + require(_verifyLinearCombinationWithGenerator(c, pk, s, uWitness), "addr(c*pk+s*g)!=_uWitness"); // Step 4. of IETF draft section 5.3 (pk corresponds to Y, seed to alpha_string) - uint256[2] memory hash = hashToCurve(pk, seed); + uint256[2] memory hash = _hashToCurve(pk, seed); // Step 6. of IETF draft section 5.3, but see note for step 5 about +/- terms - uint256[2] memory v = linearCombination(c, gamma, cGammaWitness, s, hash, sHashWitness, zInv); + uint256[2] memory v = _linearCombination(c, gamma, cGammaWitness, s, hash, sHashWitness, zInv); // Steps 7. and 8. of IETF draft section 5.3 - uint256 derivedC = scalarFromCurvePoints(hash, pk, gamma, uWitness, v); + uint256 derivedC = _scalarFromCurvePoints(hash, pk, gamma, uWitness, v); + // solhint-disable-next-line custom-errors require(c == derivedC, "invalid proof"); } } @@ -550,8 +564,8 @@ contract VRF { * @return output i.e., the random output implied by the proof * *************************************************************************** */ - function randomValueFromVRFProof(Proof memory proof, uint256 seed) internal view returns (uint256 output) { - verifyVRFProof( + function _randomValueFromVRFProof(Proof memory proof, uint256 seed) internal view returns (uint256 output) { + _verifyVRFProof( proof.pk, proof.gamma, proof.c, diff --git a/contracts/src/v0.8/vrf/VRFConsumerBase.sol b/contracts/src/v0.8/vrf/VRFConsumerBase.sol index 983a5b23cb7..7661ad40a30 100644 --- a/contracts/src/v0.8/vrf/VRFConsumerBase.sol +++ b/contracts/src/v0.8/vrf/VRFConsumerBase.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../shared/interfaces/LinkTokenInterface.sol"; +import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; -import "./VRFRequestIDBase.sol"; +import {VRFRequestIDBase} from "./VRFRequestIDBase.sol"; /** **************************************************************************** * @notice Interface for contracts using VRF randomness @@ -113,6 +113,7 @@ abstract contract VRFConsumerBase is VRFRequestIDBase { * @param requestId The Id initially returned by requestRandomness * @param randomness the VRF output */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomness(bytes32 requestId, uint256 randomness) internal virtual; /** @@ -149,6 +150,7 @@ abstract contract VRFConsumerBase is VRFRequestIDBase { * @dev concurrent requests. It is passed as the first argument to * @dev fulfillRandomness. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomness(bytes32 _keyHash, uint256 _fee) internal returns (bytes32 requestId) { LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, USER_SEED_PLACEHOLDER)); // This is the seed passed to VRFCoordinator. The oracle will mix this with @@ -165,12 +167,15 @@ abstract contract VRFConsumerBase is VRFRequestIDBase { return makeRequestId(_keyHash, vRFSeed); } + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i LinkTokenInterface internal immutable LINK; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address private immutable vrfCoordinator; // Nonces for each VRF key from which randomness has been requested. // // Must stay in sync with VRFCoordinator[_keyHash][this] + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore mapping(bytes32 => uint256) /* keyHash */ /* nonce */ private nonces; /** @@ -188,6 +193,7 @@ abstract contract VRFConsumerBase is VRFRequestIDBase { // proof. rawFulfillRandomness then calls fulfillRandomness, after validating // the origin of the call function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external { + // solhint-disable-next-line custom-errors require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill"); fulfillRandomness(requestId, randomness); } diff --git a/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol b/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol index e023373ab0f..ad7025fc980 100644 --- a/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol +++ b/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol @@ -96,6 +96,7 @@ pragma solidity ^0.8.4; */ abstract contract VRFConsumerBaseV2 { error OnlyCoordinatorCanFulfill(address have, address want); + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address private immutable vrfCoordinator; /** @@ -119,6 +120,7 @@ abstract contract VRFConsumerBaseV2 { * @param requestId The Id initially returned by requestRandomness * @param randomWords the VRF output expanded to the requested number of words */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 52b7ab295e2..5150d263a8b 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -1,20 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/BlockhashStoreInterface.sol"; -import "../interfaces/AggregatorV3Interface.sol"; -import "../interfaces/VRFCoordinatorV2Interface.sol"; -import "../interfaces/TypeAndVersionInterface.sol"; -import "../shared/interfaces/IERC677Receiver.sol"; -import "./VRF.sol"; -import "../shared/access/ConfirmedOwner.sol"; -import "./VRFConsumerBaseV2.sol"; -import "../ChainSpecificUtil.sol"; +import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; +import {BlockhashStoreInterface} from "./interfaces/BlockhashStoreInterface.sol"; +import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; +import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; +import {IERC677Receiver} from "../shared/interfaces/IERC677Receiver.sol"; +import {VRF} from "./VRF.sol"; +import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; +import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; +import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCoordinatorV2Interface, IERC677Receiver { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i LinkTokenInterface public immutable LINK; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i AggregatorV3Interface public immutable LINK_ETH_FEED; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i BlockhashStoreInterface public immutable BLOCKHASH_STORE; // We need to maintain a list of consuming addresses. @@ -312,7 +315,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo if (s_subscriptionConfigs[subId].owner == address(0)) { revert InvalidSubscription(); } - cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner); + _cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner); } /** @@ -384,10 +387,10 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // The consequence for users is that they can send requests // for invalid keyHashes which will simply not be fulfilled. uint64 nonce = currentNonce + 1; - (uint256 requestId, uint256 preSeed) = computeRequestId(keyHash, msg.sender, subId, nonce); + (uint256 requestId, uint256 preSeed) = _computeRequestId(keyHash, msg.sender, subId, nonce); s_requestCommitments[requestId] = keccak256( - abi.encode(requestId, ChainSpecificUtil.getBlockNumber(), subId, callbackGasLimit, numWords, msg.sender) + abi.encode(requestId, ChainSpecificUtil._getBlockNumber(), subId, callbackGasLimit, numWords, msg.sender) ); emit RandomWordsRequested( keyHash, @@ -413,7 +416,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo return s_requestCommitments[requestId]; } - function computeRequestId( + function _computeRequestId( bytes32 keyHash, address sender, uint64 subId, @@ -427,8 +430,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly + function _callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow @@ -457,7 +459,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo return success; } - function getRandomnessFromProof( + function _getRandomnessFromProof( Proof memory proof, RequestCommitment memory rc ) private view returns (bytes32 keyHash, uint256 requestId, uint256 randomness) { @@ -478,7 +480,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -488,7 +490,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); - randomness = VRF.randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure } /* @@ -522,7 +524,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo */ function fulfillRandomWords(Proof memory proof, RequestCommitment memory rc) external nonReentrant returns (uint96) { uint256 startGas = gasleft(); - (bytes32 keyHash, uint256 requestId, uint256 randomness) = getRandomnessFromProof(proof, rc); + (bytes32 keyHash, uint256 requestId, uint256 randomness) = _getRandomnessFromProof(proof, rc); uint256[] memory randomWords = new uint256[](rc.numWords); for (uint256 i = 0; i < rc.numWords; i++) { @@ -536,10 +538,10 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // Important to not let them exhaust the gas budget and avoid oracle payment. // Do not allow any non-view/non-pure coordinator functions to be called // during the consumers callback code via reentrancyLock. - // Note that callWithExactGas will revert if we do not have sufficient gas + // Note that _callWithExactGas will revert if we do not have sufficient gas // to give the callee their requested amount. s_config.reentrancyLock = true; - bool success = callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + bool success = _callWithExactGas(rc.callbackGasLimit, rc.sender, resp); s_config.reentrancyLock = false; // Increment the req count for fee tier selection. @@ -552,7 +554,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // We also add the flat link fee to the payment amount. // Its specified in millionths of link, if s_config.fulfillmentFlatFeeLinkPPM = 1 // 1 link / 1e6 = 1e18 juels / 1e6 = 1e12 juels. - uint96 payment = calculatePaymentAmount( + uint96 payment = _calculatePaymentAmount( startGas, s_config.gasAfterPaymentCalculation, getFeeTier(reqCount), @@ -569,19 +571,19 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo } // Get the amount of gas used for fulfillment - function calculatePaymentAmount( + function _calculatePaymentAmount( uint256 startGas, uint256 gasAfterPaymentCalculation, uint32 fulfillmentFlatFeeLinkPPM, uint256 weiPerUnitGas ) internal view returns (uint96) { int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); + weiPerUnitLink = _getFeedData(); if (weiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); @@ -592,7 +594,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo return uint96(paymentNoFee + fee); } - function getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256) { uint32 stalenessSeconds = s_config.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; @@ -763,10 +765,10 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo if (pendingRequestExists(subId)) { revert PendingRequestExists(); } - cancelSubscriptionHelper(subId, to); + _cancelSubscriptionHelper(subId, to); } - function cancelSubscriptionHelper(uint64 subId, address to) private nonReentrant { + function _cancelSubscriptionHelper(uint64 subId, address to) private nonReentrant { SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; Subscription memory sub = s_subscriptions[subId]; uint96 balance = sub.balance; @@ -793,7 +795,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; for (uint256 i = 0; i < subConfig.consumers.length; i++) { for (uint256 j = 0; j < s_provingKeyHashes.length; j++) { - (uint256 reqId, ) = computeRequestId( + (uint256 reqId, ) = _computeRequestId( s_provingKeyHashes[j], subConfig.consumers[i], subId, diff --git a/contracts/src/v0.8/vrf/VRFOwner.sol b/contracts/src/v0.8/vrf/VRFOwner.sol index 2c4adf36e8c..3b35eae8a47 100644 --- a/contracts/src/v0.8/vrf/VRFOwner.sol +++ b/contracts/src/v0.8/vrf/VRFOwner.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity ^0.8.6; import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; import {AuthorizedReceiver} from "./AuthorizedReceiver.sol"; -import "./VRFTypes.sol"; +import {VRFTypes} from "./VRFTypes.sol"; // Taken from VRFCoordinatorV2.sol // Must be abi-compatible with what's there @@ -109,6 +110,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { event RandomWordsForced(uint256 indexed requestId, uint64 indexed subId, address indexed sender); constructor(address _vrfCoordinator) ConfirmedOwner(msg.sender) { + // solhint-disable-next-line custom-errors require(_vrfCoordinator != address(0), "vrf coordinator address must be non-zero"); s_vrfCoordinator = IVRFCoordinatorV2(_vrfCoordinator); } @@ -192,7 +194,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { * @param fallbackWeiPerUnitLink fallback eth/link price in the case of a stale feed * @param feeConfig fee tier configuration */ - function setConfigPrivate( + function _setConfig( uint16 minimumRequestConfirmations, uint32 maxGasLimit, uint32 stalenessSeconds, @@ -233,7 +235,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { * @dev when too many local variables are in the same scope. * @return Config struct containing all relevant configs from the VRF coordinator. */ - function getConfigs() private view returns (Config memory) { + function _getConfigs() private view returns (Config memory) { ( uint16 minimumRequestConfirmations, uint32 maxGasLimit, @@ -282,15 +284,15 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { VRFTypes.Proof memory proof, VRFTypes.RequestCommitment memory rc ) external validateAuthorizedSender { - uint256 requestId = requestIdFromProof(proof.pk, proof.seed); + uint256 requestId = _requestIdFromProof(proof.pk, proof.seed); // Get current configs to restore them to original values after - // calling setConfigPrivate. - Config memory cfg = getConfigs(); + // calling _setConfig. + Config memory cfg = _getConfigs(); - // call setConfigPrivate with the appropriate params in order to fulfill + // call _setConfig with the appropriate params in order to fulfill // an accidentally-underfunded request. - setConfigPrivate( + _setConfig( cfg.minimumRequestConfirmations, cfg.maxGasLimit, 1, // stalenessSeconds @@ -312,7 +314,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { s_vrfCoordinator.fulfillRandomWords(proof, rc); // reset configuration back to old values. - setConfigPrivate( + _setConfig( cfg.minimumRequestConfirmations, cfg.maxGasLimit, cfg.stalenessSeconds, @@ -338,7 +340,7 @@ contract VRFOwner is ConfirmedOwner, AuthorizedReceiver { * @param proofSeed the proof seed * @dev Refer to VRFCoordinatorV2.getRandomnessFromProof for original implementation. */ - function requestIdFromProof(uint256[2] memory publicKey, uint256 proofSeed) private view returns (uint256) { + function _requestIdFromProof(uint256[2] memory publicKey, uint256 proofSeed) private view returns (uint256) { bytes32 keyHash = s_vrfCoordinator.hashOfKey(publicKey); uint256 requestId = uint256(keccak256(abi.encode(keyHash, proofSeed))); return requestId; diff --git a/contracts/src/v0.8/vrf/VRFRequestIDBase.sol b/contracts/src/v0.8/vrf/VRFRequestIDBase.sol index 7770640550e..ce0f6b1547a 100644 --- a/contracts/src/v0.8/vrf/VRFRequestIDBase.sol +++ b/contracts/src/v0.8/vrf/VRFRequestIDBase.sol @@ -16,6 +16,7 @@ contract VRFRequestIDBase { * @param _requester Address of the requesting contract * @param _nonce User-specific nonce at the time of the request */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function makeVRFInputSeed( bytes32 _keyHash, uint256 _userSeed, @@ -34,6 +35,7 @@ contract VRFRequestIDBase { * @dev Note that _vRFInputSeed is not the seed passed by the consuming * @dev contract, but the one generated by makeVRFInputSeed */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function makeRequestId(bytes32 _keyHash, uint256 _vRFInputSeed) internal pure returns (bytes32) { return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed)); } diff --git a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol index 101e1bdfe20..805c8d76cb6 100644 --- a/contracts/src/v0.8/vrf/VRFV2Wrapper.sol +++ b/contracts/src/v0.8/vrf/VRFV2Wrapper.sol @@ -1,15 +1,16 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity ^0.8.6; -import "../shared/access/ConfirmedOwner.sol"; -import "../interfaces/TypeAndVersionInterface.sol"; -import "./VRFConsumerBaseV2.sol"; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/AggregatorV3Interface.sol"; -import "../interfaces/VRFCoordinatorV2Interface.sol"; -import "../interfaces/VRFV2WrapperInterface.sol"; -import "./VRFV2WrapperConsumerBase.sol"; -import "../ChainSpecificUtil.sol"; +import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol"; +import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; +import {VRFConsumerBaseV2} from "./VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; +import {AggregatorV3Interface} from "../interfaces/AggregatorV3Interface.sol"; +import {VRFCoordinatorV2Interface} from "./interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; +import {VRFV2WrapperConsumerBase} from "./VRFV2WrapperConsumerBase.sol"; +import {ChainSpecificUtil} from "../ChainSpecificUtil.sol"; /** * @notice A wrapper for VRFCoordinatorV2 that provides an interface better suited to one-off @@ -18,9 +19,13 @@ import "../ChainSpecificUtil.sol"; contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBaseV2, VRFV2WrapperInterface { event WrapperFulfillmentFailed(uint256 indexed requestId, address indexed consumer); + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i LinkTokenInterface public immutable LINK; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i AggregatorV3Interface public immutable LINK_ETH_FEED; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i ExtendedVRFCoordinatorV2Interface public immutable COORDINATOR; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i uint64 public immutable SUBSCRIPTION_ID; /// @dev this is the size of a VRF v2 fulfillment's calldata abi-encoded in bytes. /// @dev proofSize = 13 words = 13 * 256 = 3328 bits @@ -78,10 +83,10 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas // s_keyHash is the key hash to use when requesting randomness. Fees are paid based on current gas // fees, so this should be set to the highest gas lane on the network. - bytes32 s_keyHash; + bytes32 internal s_keyHash; // s_maxNumWords is the max number of words that can be requested in a single wrapped VRF request. - uint8 s_maxNumWords; + uint8 internal s_maxNumWords; struct Callback { address callbackAddress; @@ -216,8 +221,8 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas function calculateRequestPrice( uint32 _callbackGasLimit ) external view override onlyConfiguredNotDisabled returns (uint256) { - int256 weiPerUnitLink = getFeedData(); - return calculateRequestPriceInternal(_callbackGasLimit, tx.gasprice, weiPerUnitLink); + int256 weiPerUnitLink = _getFeedData(); + return _calculateRequestPrice(_callbackGasLimit, tx.gasprice, weiPerUnitLink); } /** @@ -233,11 +238,11 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas uint32 _callbackGasLimit, uint256 _requestGasPriceWei ) external view override onlyConfiguredNotDisabled returns (uint256) { - int256 weiPerUnitLink = getFeedData(); - return calculateRequestPriceInternal(_callbackGasLimit, _requestGasPriceWei, weiPerUnitLink); + int256 weiPerUnitLink = _getFeedData(); + return _calculateRequestPrice(_callbackGasLimit, _requestGasPriceWei, weiPerUnitLink); } - function calculateRequestPriceInternal( + function _calculateRequestPrice( uint256 _gas, uint256 _requestGasPrice, int256 _weiPerUnitLink @@ -247,7 +252,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // (1e18 juels/link) * ((wei/gas * (gas)) + l1wei) / (wei/link) == 1e18 juels * wei/link / (wei/link) == 1e18 juels * wei/link * link/wei == juels // baseFee is the base fee denominated in juels (link) uint256 baseFee = (1e18 * costWei) / uint256(_weiPerUnitLink); @@ -273,16 +278,19 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas * uint16 requestConfirmations, and uint32 numWords. */ function onTokenTransfer(address _sender, uint256 _amount, bytes calldata _data) external onlyConfiguredNotDisabled { + // solhint-disable-next-line custom-errors require(msg.sender == address(LINK), "only callable from LINK"); (uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords) = abi.decode( _data, (uint32, uint16, uint32) ); - uint32 eip150Overhead = getEIP150Overhead(callbackGasLimit); - int256 weiPerUnitLink = getFeedData(); - uint256 price = calculateRequestPriceInternal(callbackGasLimit, tx.gasprice, weiPerUnitLink); + uint32 eip150Overhead = _getEIP150Overhead(callbackGasLimit); + int256 weiPerUnitLink = _getFeedData(); + uint256 price = _calculateRequestPrice(callbackGasLimit, tx.gasprice, weiPerUnitLink); + // solhint-disable-next-line custom-errors require(_amount >= price, "fee too low"); + // solhint-disable-next-line custom-errors require(numWords <= s_maxNumWords, "numWords too high"); uint256 requestId = COORDINATOR.requestRandomWords( @@ -328,21 +336,23 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas s_disabled = true; } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { Callback memory callback = s_callbacks[_requestId]; delete s_callbacks[_requestId]; + // solhint-disable-next-line custom-errors require(callback.callbackAddress != address(0), "request not found"); // This should never happen VRFV2WrapperConsumerBase c; bytes memory resp = abi.encodeWithSelector(c.rawFulfillRandomWords.selector, _requestId, _randomWords); - bool success = callWithExactGas(callback.callbackGasLimit, callback.callbackAddress, resp); + bool success = _callWithExactGas(callback.callbackGasLimit, callback.callbackAddress, resp); if (!success) { emit WrapperFulfillmentFailed(_requestId, callback.callbackAddress); } } - function getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256) { bool staleFallback = s_stalenessSeconds > 0; uint256 timestamp; int256 weiPerUnitLink; @@ -351,6 +361,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas if (staleFallback && s_stalenessSeconds < block.timestamp - timestamp) { weiPerUnitLink = s_fallbackWeiPerUnitLink; } + // solhint-disable-next-line custom-errors require(weiPerUnitLink >= 0, "Invalid LINK wei price"); return weiPerUnitLink; } @@ -358,7 +369,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas /** * @dev Calculates extra amount of gas required for running an assembly call() post-EIP150. */ - function getEIP150Overhead(uint32 gas) private pure returns (uint32) { + function _getEIP150Overhead(uint32 gas) private pure returns (uint32) { return gas / 63 + 1; } @@ -366,8 +377,7 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly + function _callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow @@ -401,7 +411,9 @@ contract VRFV2Wrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBas } modifier onlyConfiguredNotDisabled() { + // solhint-disable-next-line custom-errors require(s_configured, "wrapper is not configured"); + // solhint-disable-next-line custom-errors require(!s_disabled, "wrapper is disabled"); _; } diff --git a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol index 4c7918e8b7a..2876b19dd7b 100644 --- a/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/VRFV2WrapperInterface.sol"; +import {LinkTokenInterface} from "../shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2WrapperInterface} from "./interfaces/VRFV2WrapperInterface.sol"; /** ******************************************************************************* * @notice Interface for contracts using VRF randomness through the VRF V2 wrapper @@ -28,7 +28,9 @@ import "../interfaces/VRFV2WrapperInterface.sol"; * @dev fulfillment with the randomness result. */ abstract contract VRFV2WrapperConsumerBase { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i LinkTokenInterface internal immutable LINK; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i VRFV2WrapperInterface internal immutable VRF_V2_WRAPPER; /** @@ -52,6 +54,7 @@ abstract contract VRFV2WrapperConsumerBase { * * @return requestId is the VRF V2 request ID of the newly created randomness request. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomness( uint32 _callbackGasLimit, uint16 _requestConfirmations, @@ -72,9 +75,11 @@ abstract contract VRFV2WrapperConsumerBase { * @param _requestId is the VRF V2 request ID. * @param _randomWords is the randomness result. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal virtual; function rawFulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) external { + // solhint-disable-next-line custom-errors require(msg.sender == address(VRF_V2_WRAPPER), "only VRF V2 wrapper can fulfill"); fulfillRandomWords(_requestId, _randomWords); } diff --git a/contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol similarity index 78% rename from contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol rename to contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol index c08ac5dd0a4..06c44d4dcd1 100644 --- a/contracts/src/v0.8/dev/vrf/BatchVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/BatchVRFCoordinatorV2Plus.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT +// solhint-disable-next-line one-contract-per-file pragma solidity 0.8.6; -import "../../vrf/VRFTypes.sol"; +import {VRFTypes} from "../VRFTypes.sol"; /** * @title BatchVRFCoordinatorV2Plus @@ -9,6 +10,7 @@ import "../../vrf/VRFTypes.sol"; * @notice provided VRFCoordinatorV2Plus contract efficiently in a single transaction. */ contract BatchVRFCoordinatorV2Plus { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i IVRFCoordinatorV2Plus public immutable COORDINATOR; event ErrorReturned(uint256 indexed requestId, string reason); @@ -24,15 +26,16 @@ contract BatchVRFCoordinatorV2Plus { * @param rcs the request commitments corresponding to the randomness proofs. */ function fulfillRandomWords(VRFTypes.Proof[] memory proofs, VRFTypes.RequestCommitmentV2Plus[] memory rcs) external { + // solhint-disable-next-line custom-errors require(proofs.length == rcs.length, "input array arg lengths mismatch"); for (uint256 i = 0; i < proofs.length; i++) { try COORDINATOR.fulfillRandomWords(proofs[i], rcs[i]) returns (uint96 /* payment */) { continue; } catch Error(string memory reason) { - uint256 requestId = getRequestIdFromProof(proofs[i]); + uint256 requestId = _getRequestIdFromProof(proofs[i]); emit ErrorReturned(requestId, reason); } catch (bytes memory lowLevelData) { - uint256 requestId = getRequestIdFromProof(proofs[i]); + uint256 requestId = _getRequestIdFromProof(proofs[i]); emit RawErrorReturned(requestId, lowLevelData); } } @@ -42,7 +45,7 @@ contract BatchVRFCoordinatorV2Plus { * @notice Returns the proving key hash associated with this public key. * @param publicKey the key to return the hash of. */ - function hashOfKey(uint256[2] memory publicKey) internal pure returns (bytes32) { + function _hashOfKey(uint256[2] memory publicKey) internal pure returns (bytes32) { return keccak256(abi.encode(publicKey)); } @@ -50,8 +53,8 @@ contract BatchVRFCoordinatorV2Plus { * @notice Returns the request ID of the request associated with the given proof. * @param proof the VRF proof provided by the VRF oracle. */ - function getRequestIdFromProof(VRFTypes.Proof memory proof) internal pure returns (uint256) { - bytes32 keyHash = hashOfKey(proof.pk); + function _getRequestIdFromProof(VRFTypes.Proof memory proof) internal pure returns (uint256) { + bytes32 keyHash = _hashOfKey(proof.pk); return uint256(keccak256(abi.encode(keyHash, proof.seed))); } } diff --git a/contracts/src/v0.8/dev/vrf/BlockhashStore.sol b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol similarity index 88% rename from contracts/src/v0.8/dev/vrf/BlockhashStore.sol rename to contracts/src/v0.8/vrf/dev/BlockhashStore.sol index 107746f8019..b6389c9b15a 100644 --- a/contracts/src/v0.8/dev/vrf/BlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/BlockhashStore.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.6; -import "../../ChainSpecificUtil.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; /** * @title BlockhashStore @@ -14,14 +14,15 @@ import "../../ChainSpecificUtil.sol"; * would have to be deployed. */ contract BlockhashStore { - mapping(uint => bytes32) internal s_blockhashes; + mapping(uint256 => bytes32) internal s_blockhashes; /** * @notice stores blockhash of a given block, assuming it is available through BLOCKHASH * @param n the number of the block whose blockhash should be stored */ function store(uint256 n) public { - bytes32 h = ChainSpecificUtil.getBlockhash(uint64(n)); + bytes32 h = ChainSpecificUtil._getBlockhash(uint64(n)); + // solhint-disable-next-line custom-errors require(h != 0x0, "blockhash(n) failed"); s_blockhashes[n] = h; } @@ -30,7 +31,7 @@ contract BlockhashStore { * @notice stores blockhash of the earliest block still available through BLOCKHASH. */ function storeEarliest() external { - store(ChainSpecificUtil.getBlockNumber() - 256); + store(ChainSpecificUtil._getBlockNumber() - 256); } /** @@ -40,6 +41,7 @@ contract BlockhashStore { * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. */ function storeVerifyHeader(uint256 n, bytes memory header) public { + // solhint-disable-next-line custom-errors require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); // At this point, we know that header is the correct blockheader for block n+1. @@ -72,6 +74,7 @@ contract BlockhashStore { */ function getBlockhash(uint256 n) external view returns (bytes32) { bytes32 h = s_blockhashes[n]; + // solhint-disable-next-line custom-errors require(h != 0x0, "blockhash not found in store"); return h; } diff --git a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol similarity index 95% rename from contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol rename to contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol index c4781cbde8c..e4708bb1fcf 100644 --- a/contracts/src/v0.8/dev/vrf/SubscriptionAPI.sol +++ b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../interfaces/AggregatorV3Interface.sol"; -import "../../shared/interfaces/IERC677Receiver.sol"; -import "../interfaces/IVRFSubscriptionV2Plus.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; +import {IVRFSubscriptionV2Plus} from "./interfaces/IVRFSubscriptionV2Plus.sol"; abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscriptionV2Plus { using EnumerableSet for EnumerableSet.UintSet; @@ -151,7 +151,7 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr if (s_subscriptionConfigs[subId].owner == address(0)) { revert InvalidSubscription(); } - cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner); + _cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner); } /** @@ -392,7 +392,7 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr emit SubscriptionConsumerAdded(subId, consumer); } - function deleteSubscription(uint256 subId) internal returns (uint96 balance, uint96 nativeBalance) { + function _deleteSubscription(uint256 subId) internal returns (uint96 balance, uint96 nativeBalance) { SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; Subscription memory sub = s_subscriptions[subId]; balance = sub.balance; @@ -410,8 +410,8 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr return (balance, nativeBalance); } - function cancelSubscriptionHelper(uint256 subId, address to) internal { - (uint96 balance, uint96 nativeBalance) = deleteSubscription(subId); + function _cancelSubscriptionHelper(uint256 subId, address to) internal { + (uint96 balance, uint96 nativeBalance) = _deleteSubscription(subId); // Only withdraw LINK if the token is active and there is a balance. if (address(LINK) != address(0) && balance != 0) { diff --git a/contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol similarity index 87% rename from contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol rename to contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol index bbbc08f3a22..b1a53b57163 100644 --- a/contracts/src/v0.8/dev/vrf/TrustedBlockhashStore.sol +++ b/contracts/src/v0.8/vrf/dev/TrustedBlockhashStore.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.6; -import "../../ChainSpecificUtil.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "./BlockhashStore.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {BlockhashStore} from "./BlockhashStore.sol"; contract TrustedBlockhashStore is ConfirmedOwner, BlockhashStore { error NotInWhitelist(); @@ -46,7 +46,7 @@ contract TrustedBlockhashStore is ConfirmedOwner, BlockhashStore { uint256 recentBlockNumber, bytes32 recentBlockhash ) external { - bytes32 onChainHash = ChainSpecificUtil.getBlockhash(uint64(recentBlockNumber)); + bytes32 onChainHash = ChainSpecificUtil._getBlockhash(uint64(recentBlockNumber)); if (onChainHash != recentBlockhash) { revert InvalidRecentBlockhash(); } diff --git a/contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol similarity index 94% rename from contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol rename to contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol index 0e6e2b22016..d993f69e094 100644 --- a/contracts/src/v0.8/dev/vrf/VRFConsumerBaseV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../interfaces/IVRFMigratableConsumerV2Plus.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {IVRFCoordinatorV2Plus} from "./interfaces/IVRFCoordinatorV2Plus.sol"; +import {IVRFMigratableConsumerV2Plus} from "./interfaces/IVRFMigratableConsumerV2Plus.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; /** **************************************************************************** * @notice Interface for contracts using VRF randomness @@ -103,6 +103,8 @@ abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, Confirm error OnlyOwnerOrCoordinator(address have, address owner, address coordinator); error ZeroAddress(); + // s_vrfCoordinator should be used by consumers to make requests to vrfCoordinator + // so that coordinator reference is updated after migration IVRFCoordinatorV2Plus public s_vrfCoordinator; /** @@ -126,6 +128,7 @@ abstract contract VRFConsumerBaseV2Plus is IVRFMigratableConsumerV2Plus, Confirm * @param requestId The Id initially returned by requestRandomness * @param randomWords the VRF output expanded to the requested number of words */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF diff --git a/contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol similarity index 94% rename from contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol rename to contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol index b9666eb6a14..e05e0190bd7 100644 --- a/contracts/src/v0.8/dev/VRFConsumerBaseV2Upgradeable.sol +++ b/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Upgradeable.sol @@ -96,7 +96,7 @@ pragma solidity ^0.8.4; * @dev and so remains effective only in the case of unmodified oracle software). */ -import "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @dev The VRFConsumerBaseV2Upgradable is an upgradable variant of VRFConsumerBaseV2 @@ -106,10 +106,12 @@ import "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol" */ abstract contract VRFConsumerBaseV2Upgradeable is Initializable { error OnlyCoordinatorCanFulfill(address have, address want); + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore address private vrfCoordinator; // See https://github.com/OpenZeppelin/openzeppelin-sdk/issues/37. // Each uint256 covers a single storage slot, see https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html. + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore uint256[49] private __gap; /** @@ -117,8 +119,10 @@ abstract contract VRFConsumerBaseV2Upgradeable is Initializable { * @dev See https://docs.chain.link/docs/vrf/v2/supported-networks/ for coordinator * @dev addresses on your preferred network. */ + // solhint-disable-next-line func-name-mixedcase function __VRFConsumerBaseV2_init(address _vrfCoordinator) internal onlyInitializing { if (_vrfCoordinator == address(0)) { + // solhint-disable-next-line custom-errors revert("must give valid coordinator address"); } @@ -139,6 +143,7 @@ abstract contract VRFConsumerBaseV2Upgradeable is Initializable { * @param requestId The Id initially returned by requestRandomness * @param randomWords the VRF output expanded to the requested number of words */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF diff --git a/contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol similarity index 91% rename from contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol rename to contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol index 113f098614d..e0e46fe67b7 100644 --- a/contracts/src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol @@ -1,19 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/BlockhashStoreInterface.sol"; -import "../../interfaces/TypeAndVersionInterface.sol"; -import "../../vrf/VRF.sol"; -import "./VRFConsumerBaseV2Plus.sol"; -import "../../ChainSpecificUtil.sol"; -import "./SubscriptionAPI.sol"; -import "./libraries/VRFV2PlusClient.sol"; -import "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; -import "../interfaces/IVRFCoordinatorV2Plus.sol"; - +import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; +import {VRF} from "../../vrf/VRF.sol"; +import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "./VRFConsumerBaseV2Plus.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {SubscriptionAPI} from "./SubscriptionAPI.sol"; +import {VRFV2PlusClient} from "./libraries/VRFV2PlusClient.sol"; +import {IVRFCoordinatorV2PlusMigration} from "./interfaces/IVRFCoordinatorV2PlusMigration.sol"; +// solhint-disable-next-line no-unused-import +import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "./interfaces/IVRFCoordinatorV2Plus.sol"; + +// solhint-disable-next-line contract-name-camelcase contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { /// @dev should always be available + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i BlockhashStoreInterface public immutable BLOCKHASH_STORE; // Set this maximum to 200 to give us a 56 block window to fulfill @@ -268,14 +269,14 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // The consequence for users is that they can send requests // for invalid keyHashes which will simply not be fulfilled. uint64 nonce = currentNonce + 1; - (uint256 requestId, uint256 preSeed) = computeRequestId(req.keyHash, msg.sender, req.subId, nonce); + (uint256 requestId, uint256 preSeed) = _computeRequestId(req.keyHash, msg.sender, req.subId, nonce); VRFV2PlusClient.ExtraArgsV1 memory extraArgs = _fromBytes(req.extraArgs); bytes memory extraArgsBytes = VRFV2PlusClient._argsToBytes(extraArgs); s_requestCommitments[requestId] = keccak256( abi.encode( requestId, - ChainSpecificUtil.getBlockNumber(), + ChainSpecificUtil._getBlockNumber(), req.subId, req.callbackGasLimit, req.numWords, @@ -299,7 +300,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { return requestId; } - function computeRequestId( + function _computeRequestId( bytes32 keyHash, address sender, uint256 subId, @@ -313,8 +314,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly + function _callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow @@ -349,7 +349,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { uint256 randomness; } - function getRandomnessFromProof( + function _getRandomnessFromProof( Proof memory proof, RequestCommitment memory rc ) internal view returns (Output memory) { @@ -371,7 +371,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -381,7 +381,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); - uint256 randomness = VRF.randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + uint256 randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure return Output(keyHash, requestId, randomness); } @@ -394,7 +394,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { */ function fulfillRandomWords(Proof memory proof, RequestCommitment memory rc) external nonReentrant returns (uint96) { uint256 startGas = gasleft(); - Output memory output = getRandomnessFromProof(proof, rc); + Output memory output = _getRandomnessFromProof(proof, rc); uint256[] memory randomWords = new uint256[](rc.numWords); for (uint256 i = 0; i < rc.numWords; i++) { @@ -408,10 +408,10 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // Important to not let them exhaust the gas budget and avoid oracle payment. // Do not allow any non-view/non-pure coordinator functions to be called // during the consumers callback code via reentrancyLock. - // Note that callWithExactGas will revert if we do not have sufficient gas + // Note that _callWithExactGas will revert if we do not have sufficient gas // to give the callee their requested amount. s_config.reentrancyLock = true; - bool success = callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + bool success = _callWithExactGas(rc.callbackGasLimit, rc.sender, resp); s_config.reentrancyLock = false; // Increment the req count for the subscription. @@ -424,7 +424,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { // We want to charge users exactly for how much gas they use in their callback. // The gasAfterPaymentCalculation is meant to cover these additional operations where we // decrement the subscription balance and increment the oracles withdrawable balance. - uint96 payment = calculatePaymentAmount( + uint96 payment = _calculatePaymentAmount( startGas, s_config.gasAfterPaymentCalculation, tx.gasprice, @@ -452,7 +452,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { } } - function calculatePaymentAmount( + function _calculatePaymentAmount( uint256 startGas, uint256 gasAfterPaymentCalculation, uint256 weiPerUnitGas, @@ -460,7 +460,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { ) internal view returns (uint96) { if (nativePayment) { return - calculatePaymentAmountNative( + _calculatePaymentAmountNative( startGas, gasAfterPaymentCalculation, s_feeConfig.fulfillmentFlatFeeNativePPM, @@ -468,7 +468,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { ); } return - calculatePaymentAmountLink( + _calculatePaymentAmountLink( startGas, gasAfterPaymentCalculation, s_feeConfig.fulfillmentFlatFeeLinkPPM, @@ -476,14 +476,14 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { ); } - function calculatePaymentAmountNative( + function _calculatePaymentAmountNative( uint256 startGas, uint256 gasAfterPaymentCalculation, uint32 fulfillmentFlatFeePPM, uint256 weiPerUnitGas ) internal view returns (uint96) { // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // calculate the payment without the premium uint256 baseFeeWei = weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()); // calculate the flat fee in wei @@ -493,19 +493,19 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { } // Get the amount of gas used for fulfillment - function calculatePaymentAmountLink( + function _calculatePaymentAmountLink( uint256 startGas, uint256 gasAfterPaymentCalculation, uint32 fulfillmentFlatFeeLinkPPM, uint256 weiPerUnitGas ) internal view returns (uint96) { int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); + weiPerUnitLink = _getFeedData(); if (weiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); @@ -516,7 +516,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { return uint96(paymentNoFee + fee); } - function getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256) { uint32 stalenessSeconds = s_config.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; @@ -536,7 +536,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; for (uint256 i = 0; i < subConfig.consumers.length; i++) { for (uint256 j = 0; j < s_provingKeyHashes.length; j++) { - (uint256 reqId, ) = computeRequestId( + (uint256 reqId, ) = _computeRequestId( s_provingKeyHashes[j], subConfig.consumers[i], subId, @@ -584,7 +584,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { if (pendingRequestExists(subId)) { revert PendingRequestExists(); } - cancelSubscriptionHelper(subId, to); + _cancelSubscriptionHelper(subId, to); } /*************************************************************************** @@ -620,7 +620,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { uint96 nativeBalance; } - function isTargetRegistered(address target) internal view returns (bool) { + function _isTargetRegistered(address target) internal view returns (bool) { for (uint256 i = 0; i < s_migrationTargets.length; i++) { if (s_migrationTargets[i] == target) { return true; @@ -630,7 +630,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { } function registerMigratableCoordinator(address target) external onlyOwner { - if (isTargetRegistered(target)) { + if (_isTargetRegistered(target)) { revert CoordinatorAlreadyRegistered(target); } s_migrationTargets.push(target); @@ -652,11 +652,13 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { } function migrate(uint256 subId, address newCoordinator) external nonReentrant { - if (!isTargetRegistered(newCoordinator)) { + if (!_isTargetRegistered(newCoordinator)) { revert CoordinatorNotRegistered(newCoordinator); } (uint96 balance, uint96 nativeBalance, , address owner, address[] memory consumers) = getSubscription(subId); + // solhint-disable-next-line custom-errors require(owner == msg.sender, "Not subscription owner"); + // solhint-disable-next-line custom-errors require(!pendingRequestExists(subId), "Pending request exists"); V1MigrationData memory migrationData = V1MigrationData({ @@ -668,11 +670,12 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { nativeBalance: nativeBalance }); bytes memory encodedData = abi.encode(migrationData); - deleteSubscription(subId); + _deleteSubscription(subId); IVRFCoordinatorV2PlusMigration(newCoordinator).onMigration{value: nativeBalance}(encodedData); // Only transfer LINK if the token is active and there is a balance. if (address(LINK) != address(0) && balance != 0) { + // solhint-disable-next-line custom-errors require(LINK.transfer(address(newCoordinator), balance), "insufficient funds"); } diff --git a/contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol similarity index 93% rename from contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol rename to contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol index 91124709742..2dd44c8b1a8 100644 --- a/contracts/src/v0.8/dev/VRFSubscriptionBalanceMonitor.sol +++ b/contracts/src/v0.8/vrf/dev/VRFSubscriptionBalanceMonitor.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.6; -import "../shared/access/ConfirmedOwner.sol"; -import "../automation/interfaces/KeeperCompatibleInterface.sol"; -import "../interfaces/VRFCoordinatorV2Interface.sol"; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "@openzeppelin/contracts/security/Pausable.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AutomationCompatibleInterface as KeeperCompatibleInterface} from "../../automation/interfaces/AutomationCompatibleInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; /** * @title The VRFSubscriptionBalanceMonitor contract. @@ -197,6 +197,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @param payee the address to pay */ function withdraw(uint256 amount, address payable payee) external onlyOwner { + // solhint-disable-next-line custom-errors, reason-string require(payee != address(0)); emit FundsWithdrawn(amount, payee); LINKTOKEN.transfer(payee, amount); @@ -206,6 +207,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the LINK token address. */ function setLinkTokenAddress(address linkTokenAddress) public onlyOwner { + // solhint-disable-next-line custom-errors, reason-string require(linkTokenAddress != address(0)); emit LinkTokenAddressUpdated(address(LINKTOKEN), linkTokenAddress); LINKTOKEN = LinkTokenInterface(linkTokenAddress); @@ -215,6 +217,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the VRF coordinator address. */ function setVRFCoordinatorV2Address(address coordinatorAddress) public onlyOwner { + // solhint-disable-next-line custom-errors, reason-string require(coordinatorAddress != address(0)); emit VRFCoordinatorV2AddressUpdated(address(COORDINATOR), coordinatorAddress); COORDINATOR = VRFCoordinatorV2Interface(coordinatorAddress); @@ -224,6 +227,7 @@ contract VRFSubscriptionBalanceMonitor is ConfirmedOwner, Pausable, KeeperCompat * @notice Sets the keeper registry address. */ function setKeeperRegistryAddress(address keeperRegistryAddress) public onlyOwner { + // solhint-disable-next-line custom-errors, reason-string require(keeperRegistryAddress != address(0)); emit KeeperRegistryAddressUpdated(s_keeperRegistryAddress, keeperRegistryAddress); s_keeperRegistryAddress = keeperRegistryAddress; diff --git a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol similarity index 70% rename from contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol rename to contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol index edab249b3c6..9c3b983e300 100644 --- a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapper.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapper.sol @@ -1,60 +1,61 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../interfaces/TypeAndVersionInterface.sol"; -import "./VRFConsumerBaseV2Plus.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/AggregatorV3Interface.sol"; -import "../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../interfaces/VRFV2PlusWrapperInterface.sol"; -import "./VRFV2PlusWrapperConsumerBase.sol"; -import "../../ChainSpecificUtil.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; +import {IVRFV2PlusMigrate} from "./interfaces/IVRFV2PlusMigrate.sol"; +import {VRFConsumerBaseV2Plus} from "./VRFConsumerBaseV2Plus.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; +import {VRFV2PlusClient} from "./libraries/VRFV2PlusClient.sol"; +import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; +import {VRFV2PlusWrapperConsumerBase} from "./VRFV2PlusWrapperConsumerBase.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; /** * @notice A wrapper for VRFCoordinatorV2 that provides an interface better suited to one-off * @notice requests for randomness. */ -contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBaseV2Plus, VRFV2PlusWrapperInterface { +// solhint-disable-next-line max-states-count +contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsumerBaseV2Plus, IVRFV2PlusWrapper { event WrapperFulfillmentFailed(uint256 indexed requestId, address indexed consumer); error LinkAlreadySet(); error FailedToTransferLink(); + error IncorrectExtraArgsLength(uint16 expectedMinimumLength, uint16 actualLength); + error NativePaymentInOnTokenTransfer(); + error LINKPaymentInRequestRandomWordsInNative(); - LinkTokenInterface public s_link; - AggregatorV3Interface public s_linkNativeFeed; - ExtendedVRFCoordinatorV2PlusInterface public immutable COORDINATOR; + /* Storage Slot 1: BEGIN */ + // s_keyHash is the key hash to use when requesting randomness. Fees are paid based on current gas + // fees, so this should be set to the highest gas lane on the network. + bytes32 internal s_keyHash; + /* Storage Slot 1: END */ + + /* Storage Slot 2: BEGIN */ + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i uint256 public immutable SUBSCRIPTION_ID; - /// @dev this is the size of a VRF v2 fulfillment's calldata abi-encoded in bytes. - /// @dev proofSize = 13 words = 13 * 256 = 3328 bits - /// @dev commitmentSize = 5 words = 5 * 256 = 1280 bits - /// @dev dataSize = proofSize + commitmentSize = 4608 bits - /// @dev selector = 32 bits - /// @dev total data size = 4608 bits + 32 bits = 4640 bits = 580 bytes - uint32 public s_fulfillmentTxSizeBytes = 580; + /* Storage Slot 2: END */ + /* Storage Slot 3: BEGIN */ // 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100) // and some arithmetic operations. uint256 private constant GAS_FOR_CALL_EXACT_CHECK = 5_000; + /* Storage Slot 3: END */ + /* Storage Slot 4: BEGIN */ // lastRequestId is the request ID of the most recent VRF V2 request made by this wrapper. This // should only be relied on within the same transaction the request was made. uint256 public override lastRequestId; + /* Storage Slot 4: END */ - // Configuration fetched from VRFCoordinatorV2 - - // s_configured tracks whether this contract has been configured. If not configured, randomness - // requests cannot be made. - bool public s_configured; - - // s_disabled disables the contract when true. When disabled, new VRF requests cannot be made - // but existing ones can still be fulfilled. - bool public s_disabled; - + /* Storage Slot 5: BEGIN */ // s_fallbackWeiPerUnitLink is the backup LINK exchange rate used when the LINK/NATIVE feed is // stale. int256 private s_fallbackWeiPerUnitLink; + /* Storage Slot 5: END */ + /* Storage Slot 6: BEGIN */ // s_stalenessSeconds is the number of seconds before we consider the feed price to be stale and // fallback to fallbackWeiPerUnitLink. uint32 private s_stalenessSeconds; @@ -67,36 +68,66 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // charges. uint32 private s_fulfillmentFlatFeeNativePPM; - // Other configuration + LinkTokenInterface public s_link; + /* Storage Slot 6: END */ + /* Storage Slot 7: BEGIN */ // s_wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords // function. The cost for this gas is passed to the user. uint32 private s_wrapperGasOverhead; + // Configuration fetched from VRFCoordinatorV2 + + /// @dev this is the size of a VRF v2 fulfillment's calldata abi-encoded in bytes. + /// @dev proofSize = 13 words = 13 * 256 = 3328 bits + /// @dev commitmentSize = 5 words = 5 * 256 = 1280 bits + /// @dev dataSize = proofSize + commitmentSize = 4608 bits + /// @dev selector = 32 bits + /// @dev total data size = 4608 bits + 32 bits = 4640 bits = 580 bytes + uint32 public s_fulfillmentTxSizeBytes = 580; + // s_coordinatorGasOverhead reflects the gas overhead of the coordinator's fulfillRandomWords // function. The cost for this gas is billed to the subscription, and must therefor be included // in the pricing for wrapped requests. This includes the gas costs of proof verification and // payment calculation in the coordinator. uint32 private s_coordinatorGasOverhead; + AggregatorV3Interface public s_linkNativeFeed; + /* Storage Slot 7: END */ + + /* Storage Slot 8: BEGIN */ + // s_configured tracks whether this contract has been configured. If not configured, randomness + // requests cannot be made. + bool public s_configured; + + // s_disabled disables the contract when true. When disabled, new VRF requests cannot be made + // but existing ones can still be fulfilled. + bool public s_disabled; + // s_wrapperPremiumPercentage is the premium ratio in percentage. For example, a value of 0 // indicates no premium. A value of 15 indicates a 15 percent premium. uint8 private s_wrapperPremiumPercentage; - // s_keyHash is the key hash to use when requesting randomness. Fees are paid based on current gas - // fees, so this should be set to the highest gas lane on the network. - bytes32 s_keyHash; - // s_maxNumWords is the max number of words that can be requested in a single wrapped VRF request. - uint8 s_maxNumWords; + uint8 internal s_maxNumWords; + + uint16 private constant EXPECTED_MIN_LENGTH = 36; + /* Storage Slot 8: END */ struct Callback { address callbackAddress; uint32 callbackGasLimit; - uint256 requestGasPrice; + // Reducing requestGasPrice from uint256 to uint64 slots Callback struct + // into a single word, thus saving an entire SSTORE and leading to 21K + // gas cost saving. 18 ETH would be the max gas price we can process. + // GasPrice is unlikely to be more than 14 ETH on most chains + uint64 requestGasPrice; } + /* Storage Slot 9: BEGIN */ mapping(uint256 => Callback) /* requestID */ /* callback */ public s_callbacks; + /* Storage Slot 9: END */ + constructor(address _link, address _linkNativeFeed, address _coordinator) VRFConsumerBaseV2Plus(_coordinator) { if (_link != address(0)) { s_link = LinkTokenInterface(_link); @@ -104,12 +135,11 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume if (_linkNativeFeed != address(0)) { s_linkNativeFeed = AggregatorV3Interface(_linkNativeFeed); } - COORDINATOR = ExtendedVRFCoordinatorV2PlusInterface(_coordinator); // Create this wrapper's subscription and add itself as a consumer. - uint256 subId = ExtendedVRFCoordinatorV2PlusInterface(_coordinator).createSubscription(); + uint256 subId = s_vrfCoordinator.createSubscription(); SUBSCRIPTION_ID = subId; - ExtendedVRFCoordinatorV2PlusInterface(_coordinator).addConsumer(subId, address(this)); + s_vrfCoordinator.addConsumer(subId, address(this)); } /** @@ -155,13 +185,29 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @param _wrapperPremiumPercentage is the premium ratio in percentage for wrapper requests. * * @param _keyHash to use for requesting randomness. + * @param _maxNumWords is the max number of words that can be requested in a single wrapped VRF request + * @param _stalenessSeconds is the number of seconds before we consider the feed price to be stale + * and fallback to fallbackWeiPerUnitLink. + * + * @param _fallbackWeiPerUnitLink is the backup LINK exchange rate used when the LINK/NATIVE feed + * is stale. + * + * @param _fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2Plus + * charges. + * + * @param _fulfillmentFlatFeeNativePPM is the flat fee in millionths of native that VRFCoordinatorV2Plus + * charges. */ function setConfig( uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverhead, uint8 _wrapperPremiumPercentage, bytes32 _keyHash, - uint8 _maxNumWords + uint8 _maxNumWords, + uint32 _stalenessSeconds, + int256 _fallbackWeiPerUnitLink, + uint32 _fulfillmentFlatFeeLinkPPM, + uint32 _fulfillmentFlatFeeNativePPM ) external onlyOwner { s_wrapperGasOverhead = _wrapperGasOverhead; s_coordinatorGasOverhead = _coordinatorGasOverhead; @@ -171,9 +217,10 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume s_configured = true; // Get other configuration from coordinator - (, , s_stalenessSeconds, ) = COORDINATOR.s_config(); - s_fallbackWeiPerUnitLink = COORDINATOR.s_fallbackWeiPerUnitLink(); - (s_fulfillmentFlatFeeLinkPPM, s_fulfillmentFlatFeeNativePPM) = COORDINATOR.s_feeConfig(); + s_stalenessSeconds = _stalenessSeconds; + s_fallbackWeiPerUnitLink = _fallbackWeiPerUnitLink; + s_fulfillmentFlatFeeLinkPPM = _fulfillmentFlatFeeLinkPPM; + s_fulfillmentFlatFeeNativePPM = _fulfillmentFlatFeeNativePPM; } /** @@ -188,6 +235,9 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @return fulfillmentFlatFeeLinkPPM is the flat fee in millionths of LINK that VRFCoordinatorV2Plus * charges. * + * @return fulfillmentFlatFeeNativePPM is the flat fee in millionths of native that VRFCoordinatorV2Plus + * charges. + * * @return wrapperGasOverhead reflects the gas overhead of the wrapper's fulfillRandomWords * function. The cost for this gas is passed to the user. * @@ -210,6 +260,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume int256 fallbackWeiPerUnitLink, uint32 stalenessSeconds, uint32 fulfillmentFlatFeeLinkPPM, + uint32 fulfillmentFlatFeeNativePPM, uint32 wrapperGasOverhead, uint32 coordinatorGasOverhead, uint8 wrapperPremiumPercentage, @@ -221,6 +272,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume s_fallbackWeiPerUnitLink, s_stalenessSeconds, s_fulfillmentFlatFeeLinkPPM, + s_fulfillmentFlatFeeNativePPM, s_wrapperGasOverhead, s_coordinatorGasOverhead, s_wrapperPremiumPercentage, @@ -241,14 +293,14 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume function calculateRequestPrice( uint32 _callbackGasLimit ) external view override onlyConfiguredNotDisabled returns (uint256) { - int256 weiPerUnitLink = getFeedData(); - return calculateRequestPriceInternal(_callbackGasLimit, tx.gasprice, weiPerUnitLink); + int256 weiPerUnitLink = _getFeedData(); + return _calculateRequestPrice(_callbackGasLimit, tx.gasprice, weiPerUnitLink); } function calculateRequestPriceNative( uint32 _callbackGasLimit ) external view override onlyConfiguredNotDisabled returns (uint256) { - return calculateRequestPriceNativeInternal(_callbackGasLimit, tx.gasprice); + return _calculateRequestPriceNative(_callbackGasLimit, tx.gasprice); } /** @@ -264,24 +316,24 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume uint32 _callbackGasLimit, uint256 _requestGasPriceWei ) external view override onlyConfiguredNotDisabled returns (uint256) { - int256 weiPerUnitLink = getFeedData(); - return calculateRequestPriceInternal(_callbackGasLimit, _requestGasPriceWei, weiPerUnitLink); + int256 weiPerUnitLink = _getFeedData(); + return _calculateRequestPrice(_callbackGasLimit, _requestGasPriceWei, weiPerUnitLink); } function estimateRequestPriceNative( uint32 _callbackGasLimit, uint256 _requestGasPriceWei ) external view override onlyConfiguredNotDisabled returns (uint256) { - return calculateRequestPriceNativeInternal(_callbackGasLimit, _requestGasPriceWei); + return _calculateRequestPriceNative(_callbackGasLimit, _requestGasPriceWei); } - function calculateRequestPriceNativeInternal(uint256 _gas, uint256 _requestGasPrice) internal view returns (uint256) { + function _calculateRequestPriceNative(uint256 _gas, uint256 _requestGasPrice) internal view returns (uint256) { // costWei is the base fee denominated in wei (native) // costWei takes into account the L1 posting costs of the VRF fulfillment // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // ((wei/gas * (gas)) + l1wei) // baseFee is the base fee denominated in wei uint256 baseFee = costWei; @@ -293,7 +345,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume return feeWithFlatFee; } - function calculateRequestPriceInternal( + function _calculateRequestPrice( uint256 _gas, uint256 _requestGasPrice, int256 _weiPerUnitLink @@ -303,7 +355,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume // transaction, if we are on an L2. uint256 costWei = (_requestGasPrice * (_gas + s_wrapperGasOverhead + s_coordinatorGasOverhead) + - ChainSpecificUtil.getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); + ChainSpecificUtil._getL1CalldataGasCost(s_fulfillmentTxSizeBytes)); // (1e18 juels/link) * ((wei/gas * (gas)) + l1wei) / (wei/link) == 1e18 juels * wei/link / (wei/link) == 1e18 juels * wei/link * link/wei == juels // baseFee is the base fee denominated in juels (link) uint256 baseFee = (1e18 * costWei) / uint256(_weiPerUnitLink); @@ -329,16 +381,20 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * uint16 requestConfirmations, and uint32 numWords. */ function onTokenTransfer(address _sender, uint256 _amount, bytes calldata _data) external onlyConfiguredNotDisabled { + // solhint-disable-next-line custom-errors require(msg.sender == address(s_link), "only callable from LINK"); - (uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords) = abi.decode( + (uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, bytes memory extraArgs) = abi.decode( _data, - (uint32, uint16, uint32) + (uint32, uint16, uint32, bytes) ); - uint32 eip150Overhead = getEIP150Overhead(callbackGasLimit); - int256 weiPerUnitLink = getFeedData(); - uint256 price = calculateRequestPriceInternal(callbackGasLimit, tx.gasprice, weiPerUnitLink); + checkPaymentMode(extraArgs, true); + uint32 eip150Overhead = _getEIP150Overhead(callbackGasLimit); + int256 weiPerUnitLink = _getFeedData(); + uint256 price = _calculateRequestPrice(callbackGasLimit, tx.gasprice, weiPerUnitLink); + // solhint-disable-next-line custom-errors require(_amount >= price, "fee too low"); + // solhint-disable-next-line custom-errors require(numWords <= s_maxNumWords, "numWords too high"); VRFV2PlusClient.RandomWordsRequest memory req = VRFV2PlusClient.RandomWordsRequest({ keyHash: s_keyHash, @@ -346,25 +402,54 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume requestConfirmations: requestConfirmations, callbackGasLimit: callbackGasLimit + eip150Overhead + s_wrapperGasOverhead, numWords: numWords, - extraArgs: "" // empty extraArgs defaults to link payment + extraArgs: extraArgs // empty extraArgs defaults to link payment }); - uint256 requestId = COORDINATOR.requestRandomWords(req); + uint256 requestId = s_vrfCoordinator.requestRandomWords(req); s_callbacks[requestId] = Callback({ callbackAddress: _sender, callbackGasLimit: callbackGasLimit, - requestGasPrice: tx.gasprice + requestGasPrice: uint64(tx.gasprice) }); lastRequestId = requestId; } + function checkPaymentMode(bytes memory extraArgs, bool isLinkMode) public pure { + // If extraArgs is empty, payment mode is LINK by default + if (extraArgs.length == 0) { + if (!isLinkMode) { + revert LINKPaymentInRequestRandomWordsInNative(); + } + return; + } + if (extraArgs.length < EXPECTED_MIN_LENGTH) { + revert IncorrectExtraArgsLength(EXPECTED_MIN_LENGTH, uint16(extraArgs.length)); + } + // ExtraArgsV1 only has struct {bool nativePayment} as of now + // The following condition checks if nativePayment in abi.encode of + // ExtraArgsV1 matches the appropriate function call (onTokenTransfer + // for LINK and requestRandomWordsInNative for Native payment) + bool nativePayment = extraArgs[35] == hex"01"; + if (nativePayment && isLinkMode) { + revert NativePaymentInOnTokenTransfer(); + } + if (!nativePayment && !isLinkMode) { + revert LINKPaymentInRequestRandomWordsInNative(); + } + } + function requestRandomWordsInNative( uint32 _callbackGasLimit, uint16 _requestConfirmations, - uint32 _numWords + uint32 _numWords, + bytes calldata extraArgs ) external payable override returns (uint256 requestId) { - uint32 eip150Overhead = getEIP150Overhead(_callbackGasLimit); - uint256 price = calculateRequestPriceNativeInternal(_callbackGasLimit, tx.gasprice); + checkPaymentMode(extraArgs, false); + + uint32 eip150Overhead = _getEIP150Overhead(_callbackGasLimit); + uint256 price = _calculateRequestPriceNative(_callbackGasLimit, tx.gasprice); + // solhint-disable-next-line custom-errors require(msg.value >= price, "fee too low"); + // solhint-disable-next-line custom-errors require(_numWords <= s_maxNumWords, "numWords too high"); VRFV2PlusClient.RandomWordsRequest memory req = VRFV2PlusClient.RandomWordsRequest({ keyHash: s_keyHash, @@ -372,13 +457,13 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume requestConfirmations: _requestConfirmations, callbackGasLimit: _callbackGasLimit + eip150Overhead + s_wrapperGasOverhead, numWords: _numWords, - extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})) + extraArgs: extraArgs }); - requestId = COORDINATOR.requestRandomWords(req); + requestId = s_vrfCoordinator.requestRandomWords(req); s_callbacks[requestId] = Callback({ callbackAddress: msg.sender, callbackGasLimit: _callbackGasLimit, - requestGasPrice: tx.gasprice + requestGasPrice: uint64(tx.gasprice) }); return requestId; @@ -406,6 +491,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume */ function withdrawNative(address _recipient, uint256 _amount) external onlyOwner { (bool success, ) = payable(_recipient).call{value: _amount}(""); + // solhint-disable-next-line custom-errors require(success, "failed to withdraw native"); } @@ -424,21 +510,23 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume s_disabled = true; } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { Callback memory callback = s_callbacks[_requestId]; delete s_callbacks[_requestId]; + // solhint-disable-next-line custom-errors require(callback.callbackAddress != address(0), "request not found"); // This should never happen VRFV2PlusWrapperConsumerBase c; bytes memory resp = abi.encodeWithSelector(c.rawFulfillRandomWords.selector, _requestId, _randomWords); - bool success = callWithExactGas(callback.callbackGasLimit, callback.callbackAddress, resp); + bool success = _callWithExactGas(callback.callbackGasLimit, callback.callbackAddress, resp); if (!success) { emit WrapperFulfillmentFailed(_requestId, callback.callbackAddress); } } - function getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256) { bool staleFallback = s_stalenessSeconds > 0; uint256 timestamp; int256 weiPerUnitLink; @@ -447,6 +535,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume if (staleFallback && s_stalenessSeconds < block.timestamp - timestamp) { weiPerUnitLink = s_fallbackWeiPerUnitLink; } + // solhint-disable-next-line custom-errors require(weiPerUnitLink >= 0, "Invalid LINK wei price"); return weiPerUnitLink; } @@ -454,7 +543,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume /** * @dev Calculates extra amount of gas required for running an assembly call() post-EIP150. */ - function getEIP150Overhead(uint32 gas) private pure returns (uint32) { + function _getEIP150Overhead(uint32 gas) private pure returns (uint32) { return gas / 63 + 1; } @@ -462,8 +551,7 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly + function _callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow @@ -497,24 +585,18 @@ contract VRFV2PlusWrapper is ConfirmedOwner, TypeAndVersionInterface, VRFConsume } modifier onlyConfiguredNotDisabled() { + // solhint-disable-next-line custom-errors require(s_configured, "wrapper is not configured"); + // solhint-disable-next-line custom-errors require(!s_disabled, "wrapper is disabled"); _; } -} - -interface ExtendedVRFCoordinatorV2PlusInterface is IVRFCoordinatorV2Plus { - function s_config() - external - view - returns ( - uint16 minimumRequestConfirmations, - uint32 maxGasLimit, - uint32 stalenessSeconds, - uint32 gasAfterPaymentCalculation - ); - function s_fallbackWeiPerUnitLink() external view returns (int256); + /*************************************************************************** + * Section: Migration of VRFV2PlusWrapper to latest VRFV2PlusCoordinator + ***************************************************************************/ - function s_feeConfig() external view returns (uint32 fulfillmentFlatFeeLinkPPM, uint32 fulfillmentFlatFeeNativePPM); + function migrate(address newCoordinator) external onlyOwner { + IVRFV2PlusMigrate(address(s_vrfCoordinator)).migrate(SUBSCRIPTION_ID, newCoordinator); + } } diff --git a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol similarity index 63% rename from contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol rename to contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol index c9ddad2f778..162a658f0ed 100644 --- a/contracts/src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol +++ b/contracts/src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/VRFV2PlusWrapperInterface.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {IVRFV2PlusWrapper} from "./interfaces/IVRFV2PlusWrapper.sol"; /** * @@ -30,9 +30,10 @@ import "../interfaces/VRFV2PlusWrapperInterface.sol"; */ abstract contract VRFV2PlusWrapperConsumerBase { error LINKAlreadySet(); + error OnlyVRFWrapperCanFulfill(address have, address want); - LinkTokenInterface internal LINK; - VRFV2PlusWrapperInterface internal VRF_V2_PLUS_WRAPPER; + LinkTokenInterface internal s_linkToken; + IVRFV2PlusWrapper public immutable i_vrfV2PlusWrapper; /** * @param _link is the address of LinkToken @@ -40,10 +41,10 @@ abstract contract VRFV2PlusWrapperConsumerBase { */ constructor(address _link, address _vrfV2PlusWrapper) { if (_link != address(0)) { - LINK = LinkTokenInterface(_link); + s_linkToken = LinkTokenInterface(_link); } - VRF_V2_PLUS_WRAPPER = VRFV2PlusWrapperInterface(_vrfV2PlusWrapper); + i_vrfV2PlusWrapper = IVRFV2PlusWrapper(_vrfV2PlusWrapper); } /** @@ -51,11 +52,11 @@ abstract contract VRFV2PlusWrapperConsumerBase { * @param _link is the address of the new LINK token contract */ function setLinkToken(address _link) external { - if (address(LINK) != address(0)) { + if (address(s_linkToken) != address(0)) { revert LINKAlreadySet(); } - LINK = LinkTokenInterface(_link); + s_linkToken = LinkTokenInterface(_link); } /** @@ -70,31 +71,39 @@ abstract contract VRFV2PlusWrapperConsumerBase { * * @return requestId is the VRF V2+ request ID of the newly created randomness request. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomness( uint32 _callbackGasLimit, uint16 _requestConfirmations, - uint32 _numWords - ) internal returns (uint256 requestId) { - LINK.transferAndCall( - address(VRF_V2_PLUS_WRAPPER), - VRF_V2_PLUS_WRAPPER.calculateRequestPrice(_callbackGasLimit), - abi.encode(_callbackGasLimit, _requestConfirmations, _numWords) + uint32 _numWords, + bytes memory extraArgs + ) internal returns (uint256 requestId, uint256 reqPrice) { + reqPrice = i_vrfV2PlusWrapper.calculateRequestPrice(_callbackGasLimit); + s_linkToken.transferAndCall( + address(i_vrfV2PlusWrapper), + reqPrice, + abi.encode(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs) ); - return VRF_V2_PLUS_WRAPPER.lastRequestId(); + return (i_vrfV2PlusWrapper.lastRequestId(), reqPrice); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function requestRandomnessPayInNative( uint32 _callbackGasLimit, uint16 _requestConfirmations, - uint32 _numWords - ) internal returns (uint256 requestId) { - uint256 requestPrice = VRF_V2_PLUS_WRAPPER.calculateRequestPriceNative(_callbackGasLimit); - return - VRF_V2_PLUS_WRAPPER.requestRandomWordsInNative{value: requestPrice}( + uint32 _numWords, + bytes memory extraArgs + ) internal returns (uint256 requestId, uint256 requestPrice) { + requestPrice = i_vrfV2PlusWrapper.calculateRequestPriceNative(_callbackGasLimit); + return ( + i_vrfV2PlusWrapper.requestRandomWordsInNative{value: requestPrice}( _callbackGasLimit, _requestConfirmations, - _numWords - ); + _numWords, + extraArgs + ), + requestPrice + ); } /** @@ -104,10 +113,24 @@ abstract contract VRFV2PlusWrapperConsumerBase { * @param _requestId is the VRF V2 request ID. * @param _randomWords is the randomness result. */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal virtual; function rawFulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) external { - require(msg.sender == address(VRF_V2_PLUS_WRAPPER), "only VRF V2 Plus wrapper can fulfill"); + address vrfWrapperAddr = address(i_vrfV2PlusWrapper); + if (msg.sender != vrfWrapperAddr) { + revert OnlyVRFWrapperCanFulfill(msg.sender, vrfWrapperAddr); + } fulfillRandomWords(_requestId, _randomWords); } + + /// @notice getBalance returns the native balance of the consumer contract + function getBalance() public view returns (uint256) { + return address(this).balance; + } + + /// @notice getLinkToken returns the link token contract + function getLinkToken() public view returns (LinkTokenInterface) { + return s_linkToken; + } } diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol similarity index 93% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol index 0608340e674..846da0b1edc 100644 --- a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2Plus.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../vrf/libraries/VRFV2PlusClient.sol"; -import "./IVRFSubscriptionV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; +import {IVRFSubscriptionV2Plus} from "./IVRFSubscriptionV2Plus.sol"; // Interface that enables consumers of VRFCoordinatorV2Plus to be future-proof for upgrades // This interface is supported by subsequent versions of VRFCoordinatorV2Plus diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol similarity index 90% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol index 9892b88e691..e8fba69fc45 100644 --- a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusInternal.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./IVRFCoordinatorV2Plus.sol"; + +import {IVRFCoordinatorV2Plus} from "./IVRFCoordinatorV2Plus.sol"; // IVRFCoordinatorV2PlusInternal is the interface used by chainlink core and should // not be used by consumer conracts @@ -51,9 +52,11 @@ interface IVRFCoordinatorV2PlusInternal is IVRFCoordinatorV2Plus { uint256 zInv; } + // solhint-disable-next-line func-name-mixedcase function s_requestCommitments(uint256 requestID) external view returns (bytes32); function fulfillRandomWords(Proof memory proof, RequestCommitment memory rc) external returns (uint96); + // solhint-disable-next-line func-name-mixedcase function LINK_NATIVE_FEED() external view returns (address); } diff --git a/contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFCoordinatorV2PlusMigration.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFMigratableConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFMigratableConsumerV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFMigratableConsumerV2Plus.sol diff --git a/contracts/src/v0.8/dev/interfaces/IVRFSubscriptionV2Plus.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol similarity index 100% rename from contracts/src/v0.8/dev/interfaces/IVRFSubscriptionV2Plus.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFSubscriptionV2Plus.sol diff --git a/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusMigrate.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusMigrate.sol new file mode 100644 index 00000000000..e1a755ff574 --- /dev/null +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusMigrate.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @notice This interface is implemented by all VRF V2+ coordinators that can +/// @notice migrate subscription data to new coordinators. +interface IVRFV2PlusMigrate { + /** + * @notice migrate the provided subscription ID to the provided VRF coordinator + * @notice msg.sender must be the subscription owner and newCoordinator must + * @notice implement IVRFCoordinatorV2PlusMigration. + * @param subId the subscription ID to migrate + * @param newCoordinator the vrf coordinator to migrate to + */ + function migrate(uint256 subId, address newCoordinator) external; +} diff --git a/contracts/src/v0.8/dev/interfaces/VRFV2PlusWrapperInterface.sol b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol similarity index 97% rename from contracts/src/v0.8/dev/interfaces/VRFV2PlusWrapperInterface.sol rename to contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol index 998ccba85f3..aa3de0b6770 100644 --- a/contracts/src/v0.8/dev/interfaces/VRFV2PlusWrapperInterface.sol +++ b/contracts/src/v0.8/vrf/dev/interfaces/IVRFV2PlusWrapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -interface VRFV2PlusWrapperInterface { +interface IVRFV2PlusWrapper { /** * @return the request ID of the most recent VRF V2 request made by this wrapper. This should only * be relied option within the same transaction that the request was made. @@ -65,6 +65,7 @@ interface VRFV2PlusWrapperInterface { function requestRandomWordsInNative( uint32 _callbackGasLimit, uint16 _requestConfirmations, - uint32 _numWords + uint32 _numWords, + bytes memory extraArgs ) external payable returns (uint256 requestId); } diff --git a/contracts/src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol b/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol similarity index 100% rename from contracts/src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol rename to contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol similarity index 85% rename from contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol index 5e54636bb17..02cb15e38a4 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../../../vrf/VRF.sol"; import {VRFCoordinatorV2_5} from "../VRFCoordinatorV2_5.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +// solhint-disable-next-line contract-name-camelcase contract ExposedVRFCoordinatorV2_5 is VRFCoordinatorV2_5 { using EnumerableSet for EnumerableSet.UintSet; @@ -16,18 +16,18 @@ contract ExposedVRFCoordinatorV2_5 is VRFCoordinatorV2_5 { uint256 subId, uint64 nonce ) external pure returns (uint256, uint256) { - return computeRequestId(keyHash, sender, subId, nonce); + return _computeRequestId(keyHash, sender, subId, nonce); } function isTargetRegisteredExternal(address target) external view returns (bool) { - return isTargetRegistered(target); + return _isTargetRegistered(target); } function getRandomnessFromProofExternal( Proof calldata proof, RequestCommitment calldata rc ) external view returns (Output memory) { - return getRandomnessFromProof(proof, rc); + return _getRandomnessFromProof(proof, rc); } function getActiveSubscriptionIdsLength() external view returns (uint256) { diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol similarity index 77% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol index 7b34f96e376..6d77a5d5de0 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFConsumerV2PlusUpgradeableExample.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../../VRFConsumerBaseV2Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {VRFConsumerBaseV2Upgradeable} from "../VRFConsumerBaseV2Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFConsumerV2PlusUpgradeableExample is Initializable, VRFConsumerBaseV2Upgradeable { uint256[] public s_randomWords; @@ -20,7 +21,9 @@ contract VRFConsumerV2PlusUpgradeableExample is Initializable, VRFConsumerBaseV2 LINKTOKEN = LinkTokenInterface(_link); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + // solhint-disable-next-line custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_gasAvailable = gasleft(); @@ -37,12 +40,14 @@ contract VRFConsumerV2PlusUpgradeableExample is Initializable, VRFConsumerBaseV2 } function topUpSubscription(uint96 amount) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { COORDINATOR.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol similarity index 90% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index a8d2abfc4bc..4837411955c 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -1,17 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../../interfaces/BlockhashStoreInterface.sol"; -import "../../../interfaces/TypeAndVersionInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../../../vrf/VRF.sol"; -import "../VRFConsumerBaseV2Plus.sol"; -import "../../../ChainSpecificUtil.sol"; -import "../SubscriptionAPI.sol"; -import "../libraries/VRFV2PlusClient.sol"; -import "../../interfaces/IVRFCoordinatorV2PlusMigration.sol"; -import "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {BlockhashStoreInterface} from "../../interfaces/BlockhashStoreInterface.sol"; +// solhint-disable-next-line no-unused-import +import {IVRFCoordinatorV2Plus, IVRFSubscriptionV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {VRF} from "../../../vrf/VRF.sol"; +import {VRFConsumerBaseV2Plus, IVRFMigratableConsumerV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; +import {SubscriptionAPI} from "../SubscriptionAPI.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; +import {IVRFCoordinatorV2PlusMigration} from "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; contract VRFCoordinatorV2PlusUpgradedVersion is VRF, @@ -21,6 +20,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is { using EnumerableSet for EnumerableSet.UintSet; /// @dev should always be available + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i BlockhashStoreInterface public immutable BLOCKHASH_STORE; // Set this maximum to 200 to give us a 56 block window to fulfill @@ -36,7 +36,6 @@ contract VRFCoordinatorV2PlusUpgradedVersion is error ProvingKeyAlreadyRegistered(bytes32 keyHash); error NoSuchProvingKey(bytes32 keyHash); error InvalidLinkWeiPrice(int256 linkWei); - error InsufficientGasForConsumer(uint256 have, uint256 want); error NoCorrespondingRequest(); error IncorrectCommitment(); error BlockhashNotInStore(uint256 blockNum); @@ -57,7 +56,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is bytes extraArgs; } - mapping(bytes32 => address) /* keyHash */ /* oracle */ public s_provingKeys; + mapping(bytes32 => address) /* keyHash */ /* oracle */ internal s_provingKeys; bytes32[] public s_provingKeyHashes; mapping(uint256 => bytes32) /* requestID */ /* commitment */ public s_requestCommitments; @@ -81,9 +80,9 @@ contract VRFCoordinatorV2PlusUpgradedVersion is bool success ); - int256 public s_fallbackWeiPerUnitLink; + int256 internal s_fallbackWeiPerUnitLink; - FeeConfig public s_feeConfig; + FeeConfig internal s_feeConfig; struct FeeConfig { // Flat fee charged per fulfillment in millionths of link @@ -261,14 +260,14 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // The consequence for users is that they can send requests // for invalid keyHashes which will simply not be fulfilled. uint64 nonce = currentNonce + 1; - (uint256 requestId, uint256 preSeed) = computeRequestId(req.keyHash, msg.sender, req.subId, nonce); + (uint256 requestId, uint256 preSeed) = _computeRequestId(req.keyHash, msg.sender, req.subId, nonce); VRFV2PlusClient.ExtraArgsV1 memory extraArgs = _fromBytes(req.extraArgs); bytes memory extraArgsBytes = VRFV2PlusClient._argsToBytes(extraArgs); s_requestCommitments[requestId] = keccak256( abi.encode( requestId, - ChainSpecificUtil.getBlockNumber(), + ChainSpecificUtil._getBlockNumber(), req.subId, req.callbackGasLimit, req.numWords, @@ -292,7 +291,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is return requestId; } - function computeRequestId( + function _computeRequestId( bytes32 keyHash, address sender, uint256 subId, @@ -306,8 +305,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ - function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { - // solhint-disable-next-line no-inline-assembly + function _callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow @@ -342,7 +340,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is uint256 randomness; } - function getRandomnessFromProof( + function _getRandomnessFromProof( Proof memory proof, RequestCommitment memory rc ) internal view returns (Output memory) { @@ -364,7 +362,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert IncorrectCommitment(); } - bytes32 blockHash = ChainSpecificUtil.getBlockhash(rc.blockNum); + bytes32 blockHash = ChainSpecificUtil._getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); if (blockHash == bytes32(0)) { @@ -374,7 +372,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); - uint256 randomness = VRF.randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + uint256 randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure return Output(keyHash, requestId, randomness); } @@ -387,7 +385,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is */ function fulfillRandomWords(Proof memory proof, RequestCommitment memory rc) external nonReentrant returns (uint96) { uint256 startGas = gasleft(); - Output memory output = getRandomnessFromProof(proof, rc); + Output memory output = _getRandomnessFromProof(proof, rc); uint256[] memory randomWords = new uint256[](rc.numWords); for (uint256 i = 0; i < rc.numWords; i++) { @@ -401,10 +399,10 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // Important to not let them exhaust the gas budget and avoid oracle payment. // Do not allow any non-view/non-pure coordinator functions to be called // during the consumers callback code via reentrancyLock. - // Note that callWithExactGas will revert if we do not have sufficient gas + // Note that _callWithExactGas will revert if we do not have sufficient gas // to give the callee their requested amount. s_config.reentrancyLock = true; - bool success = callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + bool success = _callWithExactGas(rc.callbackGasLimit, rc.sender, resp); s_config.reentrancyLock = false; // Increment the req count for the subscription. @@ -417,7 +415,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is // We want to charge users exactly for how much gas they use in their callback. // The gasAfterPaymentCalculation is meant to cover these additional operations where we // decrement the subscription balance and increment the oracles withdrawable balance. - uint96 payment = calculatePaymentAmount( + uint96 payment = _calculatePaymentAmount( startGas, s_config.gasAfterPaymentCalculation, tx.gasprice, @@ -445,7 +443,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } } - function calculatePaymentAmount( + function _calculatePaymentAmount( uint256 startGas, uint256 gasAfterPaymentCalculation, uint256 weiPerUnitGas, @@ -453,7 +451,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is ) internal view returns (uint96) { if (nativePayment) { return - calculatePaymentAmountNative( + _calculatePaymentAmountNative( startGas, gasAfterPaymentCalculation, s_feeConfig.fulfillmentFlatFeeNativePPM, @@ -461,7 +459,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is ); } return - calculatePaymentAmountLink( + _calculatePaymentAmountLink( startGas, gasAfterPaymentCalculation, s_feeConfig.fulfillmentFlatFeeLinkPPM, @@ -469,14 +467,14 @@ contract VRFCoordinatorV2PlusUpgradedVersion is ); } - function calculatePaymentAmountNative( + function _calculatePaymentAmountNative( uint256 startGas, uint256 gasAfterPaymentCalculation, uint32 fulfillmentFlatFeePPM, uint256 weiPerUnitGas ) internal view returns (uint96) { // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // calculate the payment without the premium uint256 baseFeeWei = weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()); // calculate the flat fee in wei @@ -486,19 +484,19 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } // Get the amount of gas used for fulfillment - function calculatePaymentAmountLink( + function _calculatePaymentAmountLink( uint256 startGas, uint256 gasAfterPaymentCalculation, uint32 fulfillmentFlatFeeLinkPPM, uint256 weiPerUnitGas ) internal view returns (uint96) { int256 weiPerUnitLink; - weiPerUnitLink = getFeedData(); + weiPerUnitLink = _getFeedData(); if (weiPerUnitLink <= 0) { revert InvalidLinkWeiPrice(weiPerUnitLink); } // Will return non-zero on chains that have this enabled - uint256 l1CostWei = ChainSpecificUtil.getCurrentTxL1GasFees(); + uint256 l1CostWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); // (1e18 juels/link) ((wei/gas * gas) + l1wei) / (wei/link) = juels uint256 paymentNoFee = (1e18 * (weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft()) + l1CostWei)) / uint256(weiPerUnitLink); @@ -509,7 +507,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is return uint96(paymentNoFee + fee); } - function getFeedData() private view returns (int256) { + function _getFeedData() private view returns (int256) { uint32 stalenessSeconds = s_config.stalenessSeconds; bool staleFallback = stalenessSeconds > 0; uint256 timestamp; @@ -535,7 +533,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; for (uint256 i = 0; i < subConfig.consumers.length; i++) { for (uint256 j = 0; j < s_provingKeyHashes.length; j++) { - (uint256 reqId, ) = computeRequestId( + (uint256 reqId, ) = _computeRequestId( s_provingKeyHashes[j], subConfig.consumers[i], subId, @@ -583,7 +581,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is if (pendingRequestExists(subId)) { revert PendingRequestExists(); } - cancelSubscriptionHelper(subId, to); + _cancelSubscriptionHelper(subId, to); } /*************************************************************************** @@ -616,7 +614,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is uint96 nativeBalance; } - function isTargetRegistered(address target) internal view returns (bool) { + function _isTargetRegistered(address target) internal view returns (bool) { for (uint256 i = 0; i < s_migrationTargets.length; i++) { if (s_migrationTargets[i] == target) { return true; @@ -626,7 +624,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } function registerMigratableCoordinator(address target) external onlyOwner { - if (isTargetRegistered(target)) { + if (_isTargetRegistered(target)) { revert CoordinatorAlreadyRegistered(target); } s_migrationTargets.push(target); @@ -634,11 +632,13 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } function migrate(uint256 subId, address newCoordinator) external nonReentrant { - if (!isTargetRegistered(newCoordinator)) { + if (!_isTargetRegistered(newCoordinator)) { revert CoordinatorNotRegistered(newCoordinator); } (uint96 balance, uint96 nativeBalance, , address owner, address[] memory consumers) = getSubscription(subId); + // solhint-disable-next-line custom-errors require(owner == msg.sender, "Not subscription owner"); + // solhint-disable-next-line custom-errors require(!pendingRequestExists(subId), "Pending request exists"); V1MigrationData memory migrationData = V1MigrationData({ @@ -650,11 +650,12 @@ contract VRFCoordinatorV2PlusUpgradedVersion is nativeBalance: nativeBalance }); bytes memory encodedData = abi.encode(migrationData); - deleteSubscription(subId); + _deleteSubscription(subId); IVRFCoordinatorV2PlusMigration(newCoordinator).onMigration{value: nativeBalance}(encodedData); // Only transfer LINK if the token is active and there is a balance. if (address(LINK) != address(0) && balance != 0) { + // solhint-disable-next-line custom-errors require(LINK.transfer(address(newCoordinator), balance), "insufficient funds"); } @@ -670,7 +671,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is } function migrationVersion() public pure returns (uint8 version) { - return 1; + return 2; } /** @@ -699,7 +700,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert SubscriptionIDCollisionFound(); } - for (uint i = 0; i < migrationData.consumers.length; i++) { + for (uint256 i = 0; i < migrationData.consumers.length; i++) { s_consumers[migrationData.consumers[i]][migrationData.subId] = 1; } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol similarity index 93% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol index 52a5b864c6b..0204be807f5 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2PlusMigration.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; +import {IVRFCoordinatorV2PlusMigration} from "../interfaces/IVRFCoordinatorV2PlusMigration.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; /// @dev this contract is only meant for testing migration /// @dev it is a simplified example of future version (V2) of VRFCoordinatorV2Plus +// solhint-disable-next-line contract-name-camelcase contract VRFCoordinatorV2Plus_V2Example is IVRFCoordinatorV2PlusMigration { error SubscriptionIDCollisionFound(); @@ -135,10 +135,10 @@ contract VRFCoordinatorV2Plus_V2Example is IVRFCoordinatorV2PlusMigration { function requestRandomWords(VRFV2PlusClient.RandomWordsRequest calldata req) external returns (uint256 requestId) { Subscription memory sub = s_subscriptions[req.subId]; sub.reqCount = sub.reqCount + 1; - return handleRequest(msg.sender); + return _handleRequest(msg.sender); } - function handleRequest(address requester) private returns (uint256) { + function _handleRequest(address requester) private returns (uint256) { s_requestId = s_requestId + 1; uint256 requestId = s_requestId; s_requestConsumerMapping[s_requestId] = requester; diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol similarity index 63% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol index 11e899ae659..9bbb5692071 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFMaliciousConsumerV2Plus.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFMaliciousConsumerV2Plus.sol @@ -1,24 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFMaliciousConsumerV2Plus is VRFConsumerBaseV2Plus { uint256[] public s_randomWords; uint256 public s_requestId; - IVRFCoordinatorV2Plus COORDINATOR; - LinkTokenInterface LINKTOKEN; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + LinkTokenInterface internal LINKTOKEN; uint256 public s_gasAvailable; - uint256 s_subId; - bytes32 s_keyHash; + uint256 internal s_subId; + bytes32 internal s_keyHash; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2Plus(vrfCoordinator) { - COORDINATOR = IVRFCoordinatorV2Plus(vrfCoordinator); LINKTOKEN = LinkTokenInterface(link); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { s_gasAvailable = gasleft(); s_randomWords = randomWords; @@ -32,22 +32,23 @@ contract VRFMaliciousConsumerV2Plus is VRFConsumerBaseV2Plus { extraArgs: "" // empty extraArgs defaults to link payment }); // Should revert - COORDINATOR.requestRandomWords(req); + s_vrfCoordinator.requestRandomWords(req); } function createSubscriptionAndFund(uint96 amount) external { if (s_subId == 0) { - s_subId = COORDINATOR.createSubscription(); - COORDINATOR.addConsumer(s_subId, address(this)); + s_subId = s_vrfCoordinator.createSubscription(); + s_vrfCoordinator.addConsumer(s_subId, address(this)); } // Approve the link transfer. - LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); + LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { - COORDINATOR.addConsumer(s_subId, consumers[i]); + s_vrfCoordinator.addConsumer(s_subId, consumers[i]); } } @@ -61,6 +62,6 @@ contract VRFMaliciousConsumerV2Plus is VRFConsumerBaseV2Plus { numWords: 1, extraArgs: "" // empty extraArgs defaults to link payment }); - return COORDINATOR.requestRandomWords(req); + return s_vrfCoordinator.requestRandomWords(req); } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol similarity index 81% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol index 948cc17b3f3..2ef4e5c021f 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; -import "../../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; /// @notice This contract is used for testing only and should not be used for production. contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { @@ -28,11 +29,12 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { function getRandomness(uint256 requestId, uint256 idx) public view returns (uint256 randomWord) { Response memory resp = s_requests[requestId]; + // solhint-disable-next-line custom-errors require(resp.requestId != 0, "request ID is incorrect"); return resp.randomWords[idx]; } - function subscribe() internal returns (uint256) { + function _subscribe() internal returns (uint256) { if (s_subId == 0) { s_subId = s_vrfCoordinatorApiV1.createSubscription(); s_vrfCoordinatorApiV1.addConsumer(s_subId, address(this)); @@ -41,27 +43,31 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { } function createSubscriptionAndFundNative() external payable { - subscribe(); + _subscribe(); s_vrfCoordinatorApiV1.fundSubscriptionWithNative{value: msg.value}(s_subId); } function createSubscriptionAndFund(uint96 amount) external { - subscribe(); + _subscribe(); // Approve the link transfer. s_linkToken.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function topUpSubscription(uint96 amount) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); s_linkToken.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function topUpSubscriptionNative() external payable { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); s_vrfCoordinatorApiV1.fundSubscriptionWithNative{value: msg.value}(s_subId); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + // solhint-disable-next-line custom-errors require(requestId == s_recentRequestId, "request ID is incorrect"); s_requests[requestId].randomWords = randomWords; s_requests[requestId].fulfilled = true; @@ -94,6 +100,7 @@ contract VRFV2PlusConsumerExample is ConfirmedOwner, VRFConsumerBaseV2Plus { } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { s_vrfCoordinatorApiV1.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol similarity index 68% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol index 2b9ac5713cc..ed12d156f21 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusExternalSubOwnerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusExternalSubOwnerExample.sol @@ -1,26 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; /// @notice This contract is used for testing only and should not be used for production. contract VRFV2PlusExternalSubOwnerExample is VRFConsumerBaseV2Plus { - IVRFCoordinatorV2Plus COORDINATOR; - LinkTokenInterface LINKTOKEN; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + LinkTokenInterface internal LINKTOKEN; uint256[] public s_randomWords; uint256 public s_requestId; - address s_owner; + address internal s_owner; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2Plus(vrfCoordinator) { - COORDINATOR = IVRFCoordinatorV2Plus(vrfCoordinator); LINKTOKEN = LinkTokenInterface(link); s_owner = msg.sender; } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + // solhint-disable-next-line custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_randomWords = randomWords; } @@ -42,6 +43,6 @@ contract VRFV2PlusExternalSubOwnerExample is VRFConsumerBaseV2Plus { extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: nativePayment})) }); // Will revert if subscription is not funded. - s_requestId = COORDINATOR.requestRandomWords(req); + s_requestId = s_vrfCoordinator.requestRandomWords(req); } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol similarity index 82% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol index 42296ae6bf4..c1330d32237 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusLoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusLoadTestWithMetrics.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../ChainSpecificUtil.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; -import "../../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. @@ -17,13 +16,14 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made struct RequestStatus { bool fulfilled; uint256[] randomWords; - uint requestTimestamp; - uint fulfilmentTimestamp; + uint256 requestTimestamp; + uint256 fulfilmentTimestamp; uint256 requestBlockNumber; uint256 fulfilmentBlockNumber; } @@ -32,8 +32,9 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { constructor(address _vrfCoordinator) VRFConsumerBaseV2Plus(_vrfCoordinator) {} + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -75,7 +76,7 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { uint256 requestId = s_vrfCoordinator.requestRandomWords(req); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, @@ -105,8 +106,8 @@ contract VRFV2PlusLoadTestWithMetrics is VRFConsumerBaseV2Plus { returns ( bool fulfilled, uint256[] memory randomWords, - uint requestTimestamp, - uint fulfilmentTimestamp, + uint256 requestTimestamp, + uint256 fulfilmentTimestamp, uint256 requestBlockNumber, uint256 fulfilmentBlockNumber ) diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol similarity index 63% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol index b1dca81ebdf..16797bb9390 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import "../../interfaces/IVRFMigratableConsumerV2Plus.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../libraries/VRFV2PlusClient.sol"; +import {IVRFMigratableConsumerV2Plus} from "../interfaces/IVRFMigratableConsumerV2Plus.sol"; +import {IVRFCoordinatorV2Plus} from "../interfaces/IVRFCoordinatorV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFV2PlusMaliciousMigrator is IVRFMigratableConsumerV2Plus { - IVRFCoordinatorV2Plus s_vrfCoordinator; + IVRFCoordinatorV2Plus internal s_vrfCoordinator; constructor(address _vrfCoordinator) { s_vrfCoordinator = IVRFCoordinatorV2Plus(_vrfCoordinator); @@ -15,7 +15,7 @@ contract VRFV2PlusMaliciousMigrator is IVRFMigratableConsumerV2Plus { /** * @inheritdoc IVRFMigratableConsumerV2Plus */ - function setCoordinator(address _vrfCoordinator) public override { + function setCoordinator(address /* _vrfCoordinator */) public override { // try to re-enter, should revert // args don't really matter s_vrfCoordinator.requestRandomWords( diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol similarity index 60% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol index 36063533586..4e38ae39c1d 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusRevertingExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusRevertingExample.sol @@ -1,47 +1,50 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; // VRFV2RevertingExample will always revert. Used for testing only, useless in prod. contract VRFV2PlusRevertingExample is VRFConsumerBaseV2Plus { uint256[] public s_randomWords; uint256 public s_requestId; - IVRFCoordinatorV2Plus COORDINATOR; - LinkTokenInterface LINKTOKEN; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + LinkTokenInterface internal LINKTOKEN; uint256 public s_subId; uint256 public s_gasAvailable; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2Plus(vrfCoordinator) { - COORDINATOR = IVRFCoordinatorV2Plus(vrfCoordinator); LINKTOKEN = LinkTokenInterface(link); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256, uint256[] memory) internal pure override { + // solhint-disable-next-line custom-errors, reason-string revert(); } function createSubscriptionAndFund(uint96 amount) external { if (s_subId == 0) { - s_subId = COORDINATOR.createSubscription(); - COORDINATOR.addConsumer(s_subId, address(this)); + s_subId = s_vrfCoordinator.createSubscription(); + s_vrfCoordinator.addConsumer(s_subId, address(this)); } // Approve the link transfer. - LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); + LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function topUpSubscription(uint96 amount) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. - LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); + LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { - COORDINATOR.addConsumer(s_subId, consumers[i]); + s_vrfCoordinator.addConsumer(s_subId, consumers[i]); } } @@ -60,7 +63,7 @@ contract VRFV2PlusRevertingExample is VRFConsumerBaseV2Plus { numWords: numWords, extraArgs: "" // empty extraArgs defaults to link payment }); - s_requestId = COORDINATOR.requestRandomWords(req); + s_requestId = s_vrfCoordinator.requestRandomWords(req); return s_requestId; } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol similarity index 76% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol index e4cd9ae29ad..f3bf41d4f5a 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusSingleConsumerExample.sol @@ -2,14 +2,14 @@ // Example of a single consumer contract which owns the subscription. pragma solidity ^0.8.0; -import "../../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/IVRFCoordinatorV2Plus.sol"; -import "../VRFConsumerBaseV2Plus.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBaseV2Plus} from "../VRFConsumerBaseV2Plus.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; /// @notice This contract is used for testing only and should not be used for production. contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { - IVRFCoordinatorV2Plus COORDINATOR; - LinkTokenInterface LINKTOKEN; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + LinkTokenInterface internal LINKTOKEN; struct RequestConfig { uint256 subId; @@ -22,7 +22,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { RequestConfig public s_requestConfig; uint256[] public s_randomWords; uint256 public s_requestId; - address s_owner; + address internal s_owner; constructor( address vrfCoordinator, @@ -33,7 +33,6 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { bytes32 keyHash, bool nativePayment ) VRFConsumerBaseV2Plus(vrfCoordinator) { - COORDINATOR = IVRFCoordinatorV2Plus(vrfCoordinator); LINKTOKEN = LinkTokenInterface(link); s_owner = msg.sender; s_requestConfig = RequestConfig({ @@ -47,7 +46,9 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { subscribe(); } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override { + // solhint-disable-next-line custom-errors require(requestId == s_requestId, "request ID is incorrect"); s_randomWords = randomWords; } @@ -64,7 +65,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: rc.nativePayment})) }); // Will revert if subscription is not set and funded. - s_requestId = COORDINATOR.requestRandomWords(req); + s_requestId = s_vrfCoordinator.requestRandomWords(req); } // Assumes this contract owns link @@ -73,7 +74,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { // with different link costs). function fundAndRequestRandomWords(uint256 amount) external onlyOwner { RequestConfig memory rc = s_requestConfig; - LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_requestConfig.subId)); + LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_requestConfig.subId)); VRFV2PlusClient.RandomWordsRequest memory req = VRFV2PlusClient.RandomWordsRequest({ keyHash: rc.keyHash, subId: rc.subId, @@ -83,12 +84,12 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: rc.nativePayment})) }); // Will revert if subscription is not set and funded. - s_requestId = COORDINATOR.requestRandomWords(req); + s_requestId = s_vrfCoordinator.requestRandomWords(req); } // Assumes this contract owns link function topUpSubscription(uint256 amount) external onlyOwner { - LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_requestConfig.subId)); + LINKTOKEN.transferAndCall(address(s_vrfCoordinator), amount, abi.encode(s_requestConfig.subId)); } function withdraw(uint256 amount, address to) external onlyOwner { @@ -97,7 +98,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { function unsubscribe(address to) external onlyOwner { // Returns funds to this address - COORDINATOR.cancelSubscription(s_requestConfig.subId, to); + s_vrfCoordinator.cancelSubscription(s_requestConfig.subId, to); s_requestConfig.subId = 0; } @@ -107,7 +108,7 @@ contract VRFV2PlusSingleConsumerExample is VRFConsumerBaseV2Plus { // Create a subscription, current subId address[] memory consumers = new address[](1); consumers[0] = address(this); - s_requestConfig.subId = COORDINATOR.createSubscription(); - COORDINATOR.addConsumer(s_requestConfig.subId, consumers[0]); + s_requestConfig.subId = s_vrfCoordinator.createSubscription(); + s_vrfCoordinator.addConsumer(s_requestConfig.subId, consumers[0]); } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol similarity index 72% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol index 5851d2c5df7..bc0e6531631 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2PlusWrapperConsumerBase.sol"; -import "../../../shared/access/ConfirmedOwner.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../VRFV2PlusWrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); @@ -27,8 +28,9 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir uint16 _requestConfirmations, uint32 _numWords ) external onlyOwner returns (uint256 requestId) { - requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); - uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPrice(_callbackGasLimit); + bytes memory extraArgs = VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})); + uint256 paid; + (requestId, paid) = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs); s_requests[requestId] = RequestStatus({paid: paid, randomWords: new uint256[](0), fulfilled: false, native: false}); emit WrapperRequestMade(requestId, paid); return requestId; @@ -39,14 +41,17 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir uint16 _requestConfirmations, uint32 _numWords ) external onlyOwner returns (uint256 requestId) { - requestId = requestRandomnessPayInNative(_callbackGasLimit, _requestConfirmations, _numWords); - uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPriceNative(_callbackGasLimit); + bytes memory extraArgs = VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})); + uint256 paid; + (requestId, paid) = requestRandomnessPayInNative(_callbackGasLimit, _requestConfirmations, _numWords, extraArgs); s_requests[requestId] = RequestStatus({paid: paid, randomWords: new uint256[](0), fulfilled: false, native: true}); emit WrapperRequestMade(requestId, paid); return requestId; } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); s_requests[_requestId].fulfilled = true; s_requests[_requestId].randomWords = _randomWords; @@ -56,6 +61,7 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir function getRequestStatus( uint256 _requestId ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return (request.paid, request.fulfilled, request.randomWords); @@ -64,13 +70,14 @@ contract VRFV2PlusWrapperConsumerExample is VRFV2PlusWrapperConsumerBase, Confir /// @notice withdrawLink withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in juels function withdrawLink(uint256 amount) external onlyOwner { - LINK.transfer(owner(), amount); + s_linkToken.transfer(owner(), amount); } /// @notice withdrawNative withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in wei function withdrawNative(uint256 amount) external onlyOwner { (bool success, ) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line custom-errors require(success, "withdrawNative failed"); } } diff --git a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol similarity index 74% rename from contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol rename to contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol index 4f63bc0e32a..5b75bc07d6a 100644 --- a/contracts/src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperLoadTestConsumer.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2PlusWrapperConsumerBase.sol"; -import "../../../shared/access/ConfirmedOwner.sol"; -import "../../../ChainSpecificUtil.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../VRFV2PlusWrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../../ChainSpecificUtil.sol"; +import {VRFV2PlusClient} from "../libraries/VRFV2PlusClient.sol"; contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, ConfirmedOwner { uint256 public s_responseCount; @@ -12,7 +13,8 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); event WrapperRequestMade(uint256 indexed requestId, uint256 paid); @@ -21,8 +23,8 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 paid; bool fulfilled; uint256[] randomWords; - uint requestTimestamp; - uint fulfilmentTimestamp; + uint256 requestTimestamp; + uint256 fulfilmentTimestamp; uint256 requestBlockNumber; uint256 fulfilmentBlockNumber; bool native; @@ -42,11 +44,16 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint16 _requestCount ) external onlyOwner { for (uint16 i = 0; i < _requestCount; i++) { - uint256 requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); + bytes memory extraArgs = VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})); + (uint256 requestId, uint256 paid) = requestRandomness( + _callbackGasLimit, + _requestConfirmations, + _numWords, + extraArgs + ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); - uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPrice(_callbackGasLimit); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ paid: paid, fulfilled: false, @@ -70,11 +77,16 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint16 _requestCount ) external onlyOwner { for (uint16 i = 0; i < _requestCount; i++) { - uint256 requestId = requestRandomnessPayInNative(_callbackGasLimit, _requestConfirmations, _numWords); + bytes memory extraArgs = VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: true})); + (uint256 requestId, uint256 paid) = requestRandomnessPayInNative( + _callbackGasLimit, + _requestConfirmations, + _numWords, + extraArgs + ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); - uint256 paid = VRF_V2_PLUS_WRAPPER.calculateRequestPriceNative(_callbackGasLimit); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ paid: paid, fulfilled: false, @@ -91,9 +103,11 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi } } + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -123,12 +137,13 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi uint256 paid, bool fulfilled, uint256[] memory randomWords, - uint requestTimestamp, - uint fulfilmentTimestamp, + uint256 requestTimestamp, + uint256 fulfilmentTimestamp, uint256 requestBlockNumber, uint256 fulfilmentBlockNumber ) { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return ( @@ -153,23 +168,16 @@ contract VRFV2PlusWrapperLoadTestConsumer is VRFV2PlusWrapperConsumerBase, Confi /// @notice withdrawLink withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in juels function withdrawLink(uint256 amount) external onlyOwner { - LINK.transfer(owner(), amount); + s_linkToken.transfer(owner(), amount); } /// @notice withdrawNative withdraws the amount specified in amount to the owner /// @param amount the amount to withdraw, in wei function withdrawNative(uint256 amount) external onlyOwner { (bool success, ) = payable(owner()).call{value: amount}(""); + // solhint-disable-next-line custom-errors require(success, "withdrawNative failed"); } - function getWrapper() external view returns (VRFV2PlusWrapperInterface) { - return VRF_V2_PLUS_WRAPPER; - } - receive() external payable {} - - function getBalance() public view returns (uint) { - return address(this).balance; - } } diff --git a/contracts/src/v0.8/interfaces/BlockhashStoreInterface.sol b/contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/BlockhashStoreInterface.sol rename to contracts/src/v0.8/vrf/interfaces/BlockhashStoreInterface.sol diff --git a/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol b/contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol rename to contracts/src/v0.8/vrf/interfaces/VRFCoordinatorV2Interface.sol diff --git a/contracts/src/v0.8/interfaces/VRFV2WrapperInterface.sol b/contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol similarity index 100% rename from contracts/src/v0.8/interfaces/VRFV2WrapperInterface.sol rename to contracts/src/v0.8/vrf/interfaces/VRFV2WrapperInterface.sol diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorMock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol similarity index 77% rename from contracts/src/v0.8/mocks/VRFCoordinatorMock.sol rename to contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol index 7e179d5a445..6695e79b052 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorMock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorMock.sol @@ -1,15 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../vrf/VRFConsumerBase.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFConsumerBase} from "../../vrf/VRFConsumerBase.sol"; + +// solhint-disable custom-errors contract VRFCoordinatorMock { LinkTokenInterface public LINK; event RandomnessRequest(address indexed sender, bytes32 indexed keyHash, uint256 indexed seed, uint256 fee); - constructor(address linkAddress) public { + constructor(address linkAddress) { LINK = LinkTokenInterface(linkAddress); } @@ -23,6 +25,7 @@ contract VRFCoordinatorMock { bytes memory resp = abi.encodeWithSelector(v.rawFulfillRandomness.selector, requestId, randomness); uint256 b = 206000; require(gasleft() >= b, "not enough gas for consumer"); + // solhint-disable-next-line avoid-low-level-calls, no-unused-vars (bool success, ) = consumerContract.call(resp); } diff --git a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol similarity index 92% rename from contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol rename to contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol index a263a3be500..b605815f7eb 100644 --- a/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol +++ b/contracts/src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol @@ -2,10 +2,13 @@ // A mock for testing code that relies on VRFCoordinatorV2. pragma solidity ^0.8.4; -import "../shared/interfaces/LinkTokenInterface.sol"; -import "../interfaces/VRFCoordinatorV2Interface.sol"; -import "../vrf/VRFConsumerBaseV2.sol"; -import "../shared/access/ConfirmedOwner.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; + +// solhint-disable chainlink-solidity/prefix-immutable-variables-with-i +// solhint-disable custom-errors +// solhint-disable avoid-low-level-calls contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { uint96 public immutable BASE_FEE; @@ -43,22 +46,22 @@ contract VRFCoordinatorV2Mock is VRFCoordinatorV2Interface, ConfirmedOwner { bool reentrancyLock; } Config private s_config; - uint64 s_currentSubId; - uint256 s_nextRequestId = 1; - uint256 s_nextPreSeed = 100; + uint64 internal s_currentSubId; + uint256 internal s_nextRequestId = 1; + uint256 internal s_nextPreSeed = 100; struct Subscription { address owner; uint96 balance; } - mapping(uint64 => Subscription) s_subscriptions; /* subId */ /* subscription */ - mapping(uint64 => address[]) s_consumers; /* subId */ /* consumers */ + mapping(uint64 => Subscription) internal s_subscriptions; /* subId */ /* subscription */ + mapping(uint64 => address[]) internal s_consumers; /* subId */ /* consumers */ struct Request { uint64 subId; uint32 callbackGasLimit; uint32 numWords; } - mapping(uint256 => Request) s_requests; /* requestId */ /* request */ + mapping(uint256 => Request) internal s_requests; /* requestId */ /* request */ constructor(uint96 _baseFee, uint96 _gasPriceLink) ConfirmedOwner(msg.sender) { BASE_FEE = _baseFee; diff --git a/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol new file mode 100644 index 00000000000..a594e02659f --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/ChainSpecificUtilHelper.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../ChainSpecificUtil.sol"; + +/// @dev A helper contract that exposes ChainSpecificUtil methods for testing +contract ChainSpecificUtilHelper { + function getBlockhash(uint64 blockNumber) external view returns (bytes32) { + return ChainSpecificUtil._getBlockhash(blockNumber); + } + + function getBlockNumber() external view returns (uint256) { + return ChainSpecificUtil._getBlockNumber(); + } + + function getCurrentTxL1GasFees(string memory txCallData) external view returns (uint256) { + return ChainSpecificUtil._getCurrentTxL1GasFees(bytes(txCallData)); + } + + function getL1CalldataGasCost(uint256 calldataSize) external view returns (uint256) { + return ChainSpecificUtil._getL1CalldataGasCost(calldataSize); + } +} diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol index 2f063e67267..eaac0be11b1 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumer.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../VRFConsumerBase.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; contract VRFConsumer is VRFConsumerBase { uint256 public randomnessOutput; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol index 466451c7b6a..e2502fad3ed 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFConsumerV2 is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol index b99abedf3c7..930cebf46d8 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFConsumerV2UpgradeableExample.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../../dev/VRFConsumerBaseV2Upgradeable.sol"; -import "@openzeppelin/contracts-upgradeable-4.7.3/proxy/utils/Initializable.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2Upgradeable} from "../dev/VRFConsumerBaseV2Upgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; contract VRFConsumerV2UpgradeableExample is Initializable, VRFConsumerBaseV2Upgradeable { uint256[] public s_randomWords; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol index 5d336594e5e..f9385329686 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorV2TestHelper.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/AggregatorV3Interface.sol"; +import {AggregatorV3Interface} from "../../interfaces/AggregatorV3Interface.sol"; // Ideally this contract should inherit from VRFCoordinatorV2 and delegate calls to VRFCoordinatorV2 // However, due to exceeding contract size limit, the logic from VRFCoordinatorV2 is ported over to this contract contract VRFCoordinatorV2TestHelper { - uint96 s_paymentAmount; + uint96 internal s_paymentAmount; AggregatorV3Interface public immutable LINK_ETH_FEED; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol index f6b171cb508..ee2a71df71b 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFExternalSubOwnerExample.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFExternalSubOwnerExample is VRFConsumerBaseV2 { - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint256[] public s_randomWords; uint256 public s_requestId; - address s_owner; + address internal s_owner; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol index b4bf37990d7..0193e3f67f0 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestExternalSubOwner.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol index 93c75298d9e..a967c8a565e 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRFConsumerBase.sol"; -import "../../shared/interfaces/IERC677Receiver.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; /** * @title The VRFLoadTestOwnerlessConsumer contract. diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol index f11fcc0b7d0..be416e9a5cf 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFMaliciousConsumerV2.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFMaliciousConsumerV2 is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; - bytes32 s_keyHash; + bytes32 internal s_keyHash; constructor(address vrfCoordinator, address link) VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol index 0eeb5ebc8f1..a641267597c 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFOwnerlessConsumerExample.sol @@ -3,8 +3,8 @@ // contract. pragma solidity ^0.8.4; -import "../VRFConsumerBase.sol"; -import "../../shared/interfaces/IERC677Receiver.sol"; +import {VRFConsumerBase} from "../VRFConsumerBase.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; contract VRFOwnerlessConsumerExample is VRFConsumerBase, IERC677Receiver { uint256 public s_randomnessOutput; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol index b97a835a94d..344797f0df3 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFRequestIDBaseTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRFRequestIDBase.sol"; +import {VRFRequestIDBase} from "../VRFRequestIDBase.sol"; contract VRFRequestIDBaseTestHelper is VRFRequestIDBase { function makeVRFInputSeed_( diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol index d4dd7b9087a..303394ee888 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFSingleConsumerExample.sol @@ -2,13 +2,13 @@ // Example of a single consumer contract which owns the subscription. pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; contract VRFSingleConsumerExample is VRFConsumerBaseV2 { - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; struct RequestConfig { uint64 subId; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol b/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol index e2c276615a9..471b6f99301 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFSubscriptionBalanceMonitorExposed.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.6; -import "../../dev/VRFSubscriptionBalanceMonitor.sol"; +import {VRFSubscriptionBalanceMonitor} from "../dev/VRFSubscriptionBalanceMonitor.sol"; contract VRFSubscriptionBalanceMonitorExposed is VRFSubscriptionBalanceMonitor { constructor( diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol b/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol index 56a1058bf03..bcead3f0c99 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFTestHelper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../VRF.sol"; +import {VRF} from "../VRF.sol"; /** *********************************************************************** @notice Testing harness for VRF.sol, exposing its internal methods. Not to @@ -9,27 +9,27 @@ import "../VRF.sol"; */ contract VRFTestHelper is VRF { function bigModExp_(uint256 base, uint256 exponent) public view returns (uint256) { - return super.bigModExp(base, exponent); + return super._bigModExp(base, exponent); } function squareRoot_(uint256 x) public view returns (uint256) { - return super.squareRoot(x); + return super._squareRoot(x); } function ySquared_(uint256 x) public pure returns (uint256) { - return super.ySquared(x); + return super._ySquared(x); } function fieldHash_(bytes memory b) public pure returns (uint256) { - return super.fieldHash(b); + return super._fieldHash(b); } function hashToCurve_(uint256[2] memory pk, uint256 x) public view returns (uint256[2] memory) { - return super.hashToCurve(pk, x); + return super._hashToCurve(pk, x); } function ecmulVerify_(uint256[2] memory x, uint256 scalar, uint256[2] memory q) public pure returns (bool) { - return super.ecmulVerify(x, scalar, q); + return super._ecmulVerify(x, scalar, q); } function projectiveECAdd_( @@ -38,7 +38,7 @@ contract VRFTestHelper is VRF { uint256 qx, uint256 qy ) public pure returns (uint256, uint256, uint256) { - return super.projectiveECAdd(px, py, qx, qy); + return super._projectiveECAdd(px, py, qx, qy); } function affineECAdd_( @@ -46,7 +46,7 @@ contract VRFTestHelper is VRF { uint256[2] memory p2, uint256 invZ ) public pure returns (uint256[2] memory) { - return super.affineECAdd(p1, p2, invZ); + return super._affineECAdd(p1, p2, invZ); } function verifyLinearCombinationWithGenerator_( @@ -55,7 +55,7 @@ contract VRFTestHelper is VRF { uint256 s, address lcWitness ) public pure returns (bool) { - return super.verifyLinearCombinationWithGenerator(c, p, s, lcWitness); + return super._verifyLinearCombinationWithGenerator(c, p, s, lcWitness); } function linearCombination_( @@ -67,7 +67,7 @@ contract VRFTestHelper is VRF { uint256[2] memory sp2Witness, uint256 zInv ) public pure returns (uint256[2] memory) { - return super.linearCombination(c, p1, cp1Witness, s, p2, sp2Witness, zInv); + return super._linearCombination(c, p1, cp1Witness, s, p2, sp2Witness, zInv); } function scalarFromCurvePoints_( @@ -77,11 +77,11 @@ contract VRFTestHelper is VRF { address uWitness, uint256[2] memory v ) public pure returns (uint256) { - return super.scalarFromCurvePoints(hash, pk, gamma, uWitness, v); + return super._scalarFromCurvePoints(hash, pk, gamma, uWitness, v); } function isOnCurve_(uint256[2] memory p) public pure returns (bool) { - return super.isOnCurve(p); + return super._isOnCurve(p); } function verifyVRFProof_( @@ -95,10 +95,10 @@ contract VRFTestHelper is VRF { uint256[2] memory sHashWitness, uint256 zInv ) public view { - super.verifyVRFProof(pk, gamma, c, s, seed, uWitness, cGammaWitness, sHashWitness, zInv); + super._verifyVRFProof(pk, gamma, c, s, seed, uWitness, cGammaWitness, sHashWitness, zInv); } function randomValueFromVRFProof_(Proof memory proof, uint256 seed) public view returns (uint256 output) { - return super.randomValueFromVRFProof(proof, seed); + return super._randomValueFromVRFProof(proof, seed); } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol index 3fd3f4e4038..d364e5002b4 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../ChainSpecificUtil.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. @@ -19,7 +19,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made struct RequestStatus { bool fulfilled; @@ -37,7 +37,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -74,7 +74,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { _numWords ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol index 361c32706f4..dd1af80a92d 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol @@ -1,11 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../ChainSpecificUtil.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { VRFCoordinatorV2Interface public COORDINATOR; @@ -16,7 +15,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_slowestFulfillment = 0; uint256 public s_fastestFulfillment = 999; uint256 public s_lastRequestId; - mapping(uint256 => uint256) requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made struct RequestStatus { bool fulfilled; @@ -38,7 +37,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { - uint256 fulfilmentBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; uint256 requestDelayInMillions = requestDelay * 1_000_000; @@ -74,7 +73,7 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { _numWords ); s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil.getBlockNumber(); + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); s_requests[requestId] = RequestStatus({ randomWords: new uint256[](0), fulfilled: false, diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol index 72be535a000..4eccafa37ef 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2RevertingExample.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFCoordinatorV2Interface.sol"; -import "../VRFConsumerBaseV2.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; // VRFV2RevertingExample will always revert. Used for testing only, useless in prod. contract VRFV2RevertingExample is VRFConsumerBaseV2 { uint256[] public s_randomWords; uint256 public s_requestId; - VRFCoordinatorV2Interface COORDINATOR; - LinkTokenInterface LINKTOKEN; + VRFCoordinatorV2Interface internal COORDINATOR; + LinkTokenInterface internal LINKTOKEN; uint64 public s_subId; uint256 public s_gasAvailable; @@ -20,6 +20,7 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function fulfillRandomWords(uint256, uint256[] memory) internal pure override { + // solhint-disable-next-line custom-errors, reason-string revert(); } @@ -33,12 +34,14 @@ contract VRFV2RevertingExample is VRFConsumerBaseV2 { } function topUpSubscription(uint96 amount) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "sub not set"); // Approve the link transfer. LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(s_subId)); } function updateSubscription(address[] memory consumers) external { + // solhint-disable-next-line custom-errors require(s_subId != 0, "subID not set"); for (uint256 i = 0; i < consumers.length; i++) { COORDINATOR.addConsumer(s_subId, consumers[i]); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol index 7ab54ee9fa3..563a5b09288 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); @@ -33,6 +33,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); s_requests[_requestId].fulfilled = true; s_requests[_requestId].randomWords = _randomWords; @@ -42,6 +43,7 @@ contract VRFV2WrapperConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner function getRequestStatus( uint256 _requestId ) external view returns (uint256 paid, bool fulfilled, uint256[] memory randomWords) { + // solhint-disable-next-line custom-errors require(s_requests[_requestId].paid > 0, "request not found"); RequestStatus memory request = s_requests[_requestId]; return (request.paid, request.fulfilled, request.randomWords); diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol index e6747820fdb..353027d5570 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperOutOfGasConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperOutOfGasConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { constructor( @@ -18,7 +18,7 @@ contract VRFV2WrapperOutOfGasConsumerExample is VRFV2WrapperConsumerBase, Confir return requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); } - function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal view override { + function fulfillRandomWords(uint256 /* _requestId */, uint256[] memory /* _randomWords */) internal view override { while (gasleft() > 0) {} } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol index c3699a1d74b..d78992acfd8 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperRevertingConsumerExample.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "../VRFV2WrapperConsumerBase.sol"; -import "../../shared/access/ConfirmedOwner.sol"; +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; contract VRFV2WrapperRevertingConsumerExample is VRFV2WrapperConsumerBase, ConfirmedOwner { constructor( @@ -18,7 +18,7 @@ contract VRFV2WrapperRevertingConsumerExample is VRFV2WrapperConsumerBase, Confi return requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); } - function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal pure override { + function fulfillRandomWords(uint256 /* _requestId */, uint256[] memory /* _randomWords */) internal pure override { revert("reverting example"); } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol index ae0f9eac83c..3bae36f58f1 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperUnderFundingConsumer.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../../shared/access/ConfirmedOwner.sol"; -import "../../shared/interfaces/LinkTokenInterface.sol"; -import "../../interfaces/VRFV2WrapperInterface.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; contract VRFV2WrapperUnderFundingConsumer is ConfirmedOwner { LinkTokenInterface internal immutable LINK; diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFv2Consumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFv2Consumer.sol new file mode 100644 index 00000000000..4ec7ad081b1 --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFv2Consumer.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// An example of a consumer contract that relies on a subscription for funding. +pragma solidity 0.8.6; + +import "../interfaces/VRFCoordinatorV2Interface.sol"; +import "../VRFConsumerBaseV2.sol"; +import "../../shared/access/ConfirmedOwner.sol"; + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +contract VRFv2Consumer is VRFConsumerBaseV2, ConfirmedOwner { + event RequestSent(uint256 requestId, uint32 numWords); + event RequestFulfilled(uint256 requestId, uint256[] randomWords); + + struct RequestStatus { + bool fulfilled; // whether the request has been successfully fulfilled + bool exists; // whether a requestId exists + uint256[] randomWords; + } + mapping(uint256 => RequestStatus) public s_requests; /* requestId --> requestStatus */ + VRFCoordinatorV2Interface COORDINATOR; + + // past requests Id. + uint256[] public requestIds; + uint256 public lastRequestId; + + constructor(address vrfCoordinator) VRFConsumerBaseV2(vrfCoordinator) ConfirmedOwner(msg.sender) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + } + + // Assumes the subscription is funded sufficiently. + function requestRandomWords( + uint64 subId, + uint32 callbackGasLimit, + uint16 requestConfirmations, + uint32 numWords, + bytes32 keyHash + ) external onlyOwner returns (uint256 requestId) { + // Will revert if subscription is not set and funded. + requestId = COORDINATOR.requestRandomWords(keyHash, subId, requestConfirmations, callbackGasLimit, numWords); + s_requests[requestId] = RequestStatus({randomWords: new uint256[](0), exists: true, fulfilled: false}); + requestIds.push(requestId); + lastRequestId = requestId; + emit RequestSent(requestId, numWords); + return requestId; + } + + function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + require(s_requests[_requestId].exists, "request not found"); + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + emit RequestFulfilled(_requestId, _randomWords); + } + + function getRequestStatus(uint256 _requestId) external view returns (bool fulfilled, uint256[] memory randomWords) { + require(s_requests[_requestId].exists, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return (request.fulfilled, request.randomWords); + } +} diff --git a/contracts/test/v0.8/VRFD20.test.ts b/contracts/test/v0.8/VRFD20.test.ts index 6183658336f..f1c1278b89a 100644 --- a/contracts/test/v0.8/VRFD20.test.ts +++ b/contracts/test/v0.8/VRFD20.test.ts @@ -34,7 +34,7 @@ before(async () => { roles.defaultAccount, ) vrfCoordinatorMockFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/VRFCoordinatorMock.sol:VRFCoordinatorMock', + 'src/v0.8/vrf/mocks/VRFCoordinatorMock.sol:VRFCoordinatorMock', roles.defaultAccount, ) vrfD20Factory = await ethers.getContractFactory( diff --git a/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts b/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts index ba026fa18d9..31d1ba297e0 100644 --- a/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistry1_2.test.ts @@ -28,7 +28,7 @@ import { toWei } from '../../test-helpers/helpers' const BYTECODE = KeeperRegistryFactory.bytecode const BYTECODE_CHECKSUM = - '0x35bd8b5535ae41d43d47b0a9a9e11e9942bdd51daa4ec6a9e563276f4f75ea32' + '0x8e465b93eae52724b7edbef5bc133c96520dad33f959373e5d026549ca40158c' describe('KeeperRegistry1_2 - Frozen [ @skip-coverage ]', () => { it('has not changed', () => { diff --git a/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts b/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts index eee4344b461..21cb1618254 100644 --- a/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts +++ b/contracts/test/v0.8/automation/KeeperRegistry1_3.test.ts @@ -34,7 +34,7 @@ import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' const BYTECODE = KeeperRegistryFactory.bytecode const BYTECODE_CHECKSUM = - '0x5ef7140f5c4ec2d62f8ac3d5c4385b7e40c3441fb1e4073a9545fae5f12a0ec5' + '0x7e831ebc4e043fc2946449e11f0d170ba5b6085b213591973c437bc5109b1582' describe('KeeperRegistry1_3 - Frozen [ @skip-coverage ]', () => { it('has not changed', () => { diff --git a/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts index ad1b549acca..4d9ddefd5bf 100644 --- a/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts +++ b/contracts/test/v0.8/dev/ArbitrumSequencerUptimeFeed.test.ts @@ -44,7 +44,7 @@ describe('ArbitrumSequencerUptimeFeed', () => { accessController = await accessControllerFactory.deploy() const flagsHistoryFactory = await ethers.getContractFactory( - 'src/v0.8/dev/Flags.sol:Flags', + 'src/v0.8/l2ep/dev/Flags.sol:Flags', deployer, ) flags = await flagsHistoryFactory.deploy( diff --git a/contracts/test/v0.8/dev/AuthorizedOriginReceiver.test.ts b/contracts/test/v0.8/dev/AuthorizedOriginReceiver.test.ts deleted file mode 100644 index dc6406422de..00000000000 --- a/contracts/test/v0.8/dev/AuthorizedOriginReceiver.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../../test-helpers/setup' - -let authorizedOriginReceiverFactory: ContractFactory -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - - authorizedOriginReceiverFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedOriginReceiverTestHelper.sol:AuthorizedOriginReceiverTestHelper', - roles.defaultAccount, - ) -}) - -describe('AuthorizedOriginReceiverTestHelper', () => { - let receiver: Contract - - beforeEach(async () => { - receiver = await authorizedOriginReceiverFactory - .connect(roles.defaultAccount) - .deploy() - }) - - describe('AuthorizedOriginReceiver', () => { - it('#addAuthorizedSenders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2]) - }) - - it('#addAuthorizedSenders emits AuthorizedSendersChanged', async () => { - const { personas } = await getUsers() - const owner = await personas.Default.getAddress() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])) - .to.emit(receiver, 'AuthorizedSendersChanged') - .withArgs([addr1, addr2], owner) - }) - - it('#addAuthorizedSenders empty list', async () => { - await expect(receiver.addAuthorizedSenders([])).to.be.revertedWith( - 'EmptySendersList', - ) - }) - - it('#addAuthorizedSenders new senders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - const addr3 = await personas.Neil.getAddress() - const addr4 = await personas.Ned.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - await expect(receiver.addAuthorizedSenders([addr3, addr4])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2, addr3, addr4]) - }) - - it('#addAuthorizedSenders removes duplicate new senders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - const addr3 = await personas.Neil.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - await expect(receiver.addAuthorizedSenders([addr2, addr3])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2, addr3]) - }) - - it('#remove AuthorizedSenders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2]) - - await expect(receiver.removeAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - const sendersAfterRemove = - await receiver.callStatic.getAuthorizedSenders() - expect(sendersAfterRemove).to.be.deep.equal([]) - }) - - it('#addAuthorizedSenders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2]) - }) - - it('#isAuthorizedSender', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.addAuthorizedSenders([addr1])).not.to.be.reverted - - expect(await receiver.callStatic.isAuthorizedSender(addr1)).to.be.equal( - true, - ) - expect(await receiver.callStatic.isAuthorizedSender(addr2)).to.be.equal( - false, - ) - }) - }) - - describe('#verifyValidateAuthorizedSender', () => { - it('Should revert for empty state', async () => { - await expect( - receiver.verifyValidateAuthorizedSender(), - ).to.be.revertedWith('UnauthorizedSender') - }) - - it('#validateAuthorizedSender modifier', async () => { - const { personas } = await getUsers() - - await expect( - receiver.addAuthorizedSenders([ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - ]), - ).not.to.be.reverted - - expect( - await receiver - .connect(personas.Carol) - .callStatic.verifyValidateAuthorizedSender(), - ).to.be.equal(true) - expect( - await receiver - .connect(personas.Nancy) - .callStatic.verifyValidateAuthorizedSender(), - ).to.be.equal(true) - await expect( - receiver.connect(personas.Neil).verifyValidateAuthorizedSender(), - ).to.be.revertedWith('UnauthorizedSender') - }) - - it('Should revert addAuthorizedSenders if cannot set', async () => { - const { personas } = await getUsers() - - await expect(receiver.changeSetAuthorizedSender(false)).not.to.be.reverted - - await expect( - receiver.addAuthorizedSenders([ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - ]), - ).to.be.revertedWith('NotAllowedToSetSenders') - }) - }) -}) diff --git a/contracts/test/v0.8/dev/AuthorizedReceiver.test.ts b/contracts/test/v0.8/dev/AuthorizedReceiver.test.ts deleted file mode 100644 index ca9951e6889..00000000000 --- a/contracts/test/v0.8/dev/AuthorizedReceiver.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../../test-helpers/setup' - -let authorizedReceiverFactory: ContractFactory -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - - authorizedReceiverFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/AuthorizedReceiverTestHelper.sol:AuthorizedReceiverTestHelper', - roles.defaultAccount, - ) -}) - -describe('AuthorizedReceiverTestHelper', () => { - let receiver: Contract - - beforeEach(async () => { - receiver = await authorizedReceiverFactory - .connect(roles.defaultAccount) - .deploy() - }) - - describe('AuthorizedReceiver', () => { - it('#setAuthorizedSenders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.setAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr1, addr2]) - }) - - it('#setAuthorizedSenders emits AuthorizedSendersChanged', async () => { - const { personas } = await getUsers() - const owner = await personas.Default.getAddress() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.setAuthorizedSenders([addr1, addr2])) - .to.emit(receiver, 'AuthorizedSendersChanged') - .withArgs([addr1, addr2], owner) - }) - - it('#setAuthorizedSenders empty list', async () => { - await expect(receiver.setAuthorizedSenders([])).to.be.revertedWith( - 'EmptySendersList', - ) - }) - - it('#setAuthorizedSenders new senders', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - const addr3 = await personas.Neil.getAddress() - const addr4 = await personas.Ned.getAddress() - - await expect(receiver.setAuthorizedSenders([addr1, addr2])).not.to.be - .reverted - - await expect(receiver.setAuthorizedSenders([addr3, addr4])).not.to.be - .reverted - - const senders = await receiver.callStatic.getAuthorizedSenders() - expect(senders).to.be.deep.equal([addr3, addr4]) - }) - - it('#isAuthorizedSender', async () => { - const { personas } = await getUsers() - const addr1 = await personas.Carol.getAddress() - const addr2 = await personas.Nancy.getAddress() - - await expect(receiver.setAuthorizedSenders([addr1])).not.to.be.reverted - - expect(await receiver.callStatic.isAuthorizedSender(addr1)).to.be.equal( - true, - ) - expect(await receiver.callStatic.isAuthorizedSender(addr2)).to.be.equal( - false, - ) - }) - }) - - describe('#verifyValidateAuthorizedSender', () => { - it('Should revert for empty state', async () => { - await expect( - receiver.verifyValidateAuthorizedSender(), - ).to.be.revertedWith('UnauthorizedSender') - }) - - it('#validateAuthorizedSender modifier', async () => { - const { personas } = await getUsers() - - await expect( - receiver.setAuthorizedSenders([ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - ]), - ).not.to.be.reverted - - expect( - await receiver - .connect(personas.Carol) - .callStatic.verifyValidateAuthorizedSender(), - ).to.be.equal(true) - expect( - await receiver - .connect(personas.Nancy) - .callStatic.verifyValidateAuthorizedSender(), - ).to.be.equal(true) - await expect( - receiver.connect(personas.Neil).verifyValidateAuthorizedSender(), - ).to.be.revertedWith('UnauthorizedSender') - }) - - it('Should revert setAuthorizedSenders if cannot set', async () => { - const { personas } = await getUsers() - - await expect(receiver.changeSetAuthorizedSender(false)).not.to.be.reverted - - await expect( - receiver.setAuthorizedSenders([ - await personas.Carol.getAddress(), - await personas.Nancy.getAddress(), - ]), - ).to.be.revertedWith('NotAllowedToSetSenders') - }) - }) -}) diff --git a/contracts/test/v0.8/dev/DerivedPriceFeed.test.ts b/contracts/test/v0.8/dev/DerivedPriceFeed.test.ts deleted file mode 100644 index 5171a44d1f5..00000000000 --- a/contracts/test/v0.8/dev/DerivedPriceFeed.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { ethers } from 'hardhat' -import { BigNumber, ContractFactory } from 'ethers' -import { expect } from 'chai' -import { describe } from 'mocha' - -describe('DerivedPriceFeed', () => { - let mockAggFactory: ContractFactory - let derivedFeedFactory: ContractFactory - before(async () => { - const accounts = await ethers.getSigners() - mockAggFactory = await ethers.getContractFactory( - 'src/v0.7/tests/MockV3Aggregator.sol:MockV3Aggregator', - accounts[0], - ) - derivedFeedFactory = await ethers.getContractFactory( - 'src/v0.8/dev/DerivedPriceFeed.sol:DerivedPriceFeed', - accounts[0], - ) - }) - - it('reverts on getRoundData', async () => { - let base = await mockAggFactory.deploy(8, 10e8) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 8, - ) - - await expect(derived.getRoundData(1)).to.be.reverted - }) - - it('returns decimals', async () => { - let base = await mockAggFactory.deploy(8, 10e8) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 9, - ) - - await expect(await derived.decimals()).to.equal(9) - }) - - describe('calculates price', async () => { - it('when all decimals are the same', async () => { - let base = await mockAggFactory.deploy(8, 10e8) // 10 - let quote = await mockAggFactory.deploy(8, 5e8) // 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 8, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 2e8 /* 2 */, - ) - }) - - it('when all decimals are the same 2', async () => { - let base = await mockAggFactory.deploy(8, 3e8) // 3 - let quote = await mockAggFactory.deploy(8, 15e8) // 15 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 8, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 0.2e8 /* 0.2 */, - ) - }) - - it('when result decimals are higher', async () => { - let base = await mockAggFactory.deploy(8, 10e8) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 12, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 2e12 /* 2 */, - ) - }) - - it('when result decimals are lower', async () => { - let base = await mockAggFactory.deploy(8, 10e8) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 6, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 2e6 /* 2 */, - ) - }) - - it('base decimals are higher', async () => { - let base = await mockAggFactory.deploy( - 16, - BigNumber.from('100000000000000000'), - ) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 10, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 2e10 /* 2 */, - ) - }) - - it('base decimals are lower', async () => { - let base = await mockAggFactory.deploy(6, 10e6) // Price = 10 - let quote = await mockAggFactory.deploy(8, 5e8) // Price = 5 - - let derived = await derivedFeedFactory.deploy( - base.address, - quote.address, - 10, - ) - - await expect((await derived.latestRoundData()).answer).to.equal( - 2e10 /* 2 */, - ) - }) - }) -}) diff --git a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts index b0a2a10b201..04771e4ef7f 100644 --- a/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts +++ b/contracts/test/v0.8/dev/VRFCoordinatorV2Mock.test.ts @@ -23,7 +23,7 @@ describe('VRFCoordinatorV2Mock', () => { random = accounts[2] const vrfCoordinatorV2MockFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/VRFCoordinatorV2Mock.sol:VRFCoordinatorV2Mock', + 'src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol:VRFCoordinatorV2Mock', accounts[0], ) vrfCoordinatorV2Mock = await vrfCoordinatorV2MockFactory.deploy( diff --git a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol b/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol index acdc6773642..8e43527af53 100644 --- a/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol +++ b/contracts/test/v0.8/foundry/transmission/EIP_712_1014_4337.t.sol @@ -1,18 +1,18 @@ pragma solidity ^0.8.15; import "../BaseTest.t.sol"; -import "../../../../src/v0.8/dev/transmission/ERC-4337/SmartContractAccountFactory.sol"; -import "../../../../src/v0.8/dev/transmission/testhelpers/SmartContractAccountHelper.sol"; -import "../../../../src/v0.8/dev/transmission/ERC-4337/SCA.sol"; -import "../../../../src/v0.8/dev/transmission/testhelpers/Greeter.sol"; -import "../../../../src/v0.8/dev/transmission/ERC-4337/Paymaster.sol"; +import "../../../../src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol"; +import "../../../../src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol"; +import "../../../../src/v0.8/transmission/dev/ERC-4337/SCA.sol"; +import "../../../../src/v0.8/transmission/dev/testhelpers/Greeter.sol"; +import "../../../../src/v0.8/transmission/dev/ERC-4337/Paymaster.sol"; import "../../../../src/v0.8/vendor/entrypoint/interfaces/UserOperation.sol"; import "../../../../src/v0.8/vendor/entrypoint/core/EntryPoint.sol"; import "../../../../src/v0.8/vendor/entrypoint/interfaces/IEntryPoint.sol"; -import "../../../../src/v0.8/dev/transmission/ERC-4337/SCALibrary.sol"; +import "../../../../src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol"; import "../../../../src/v0.8/mocks/MockLinkToken.sol"; import "../../../../src/v0.8/shared/interfaces/LinkTokenInterface.sol"; -import "../../../../src/v0.8/mocks/VRFCoordinatorMock.sol"; +import "../../../../src/v0.8/vrf/mocks/VRFCoordinatorMock.sol"; import "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import "../../../../src/v0.8/vrf/testhelpers/VRFConsumer.sol"; @@ -135,7 +135,7 @@ contract EIP_712_1014_4337 is BaseTest { // Sign user operation. bytes32 userOpHash = entryPoint.getUserOpHash(op); - bytes32 fullHash = SCALibrary.getUserOpFullHash(userOpHash, toDeployAddress); + bytes32 fullHash = SCALibrary._getUserOpFullHash(userOpHash, toDeployAddress); (uint8 v, bytes32 r, bytes32 s) = vm.sign(END_USER_PKEY, fullHash); op.signature = abi.encodePacked(r, s, v - 27); @@ -195,7 +195,7 @@ contract EIP_712_1014_4337 is BaseTest { // Sign user operation. bytes32 userOpHash = entryPoint.getUserOpHash(op); - bytes32 fullHash = SCALibrary.getUserOpFullHash(userOpHash, toDeployAddress); + bytes32 fullHash = SCALibrary._getUserOpFullHash(userOpHash, toDeployAddress); (uint8 v, bytes32 r, bytes32 s) = vm.sign(END_USER_PKEY, fullHash); op.signature = abi.encodePacked(r, s, v - 27); @@ -260,7 +260,7 @@ contract EIP_712_1014_4337 is BaseTest { // Sign user operation. bytes32 userOpHash = entryPoint.getUserOpHash(op); - bytes32 fullHash = SCALibrary.getUserOpFullHash(userOpHash, toDeployAddress); + bytes32 fullHash = SCALibrary._getUserOpFullHash(userOpHash, toDeployAddress); (uint8 v, bytes32 r, bytes32 s) = vm.sign(END_USER_PKEY, fullHash); op.signature = abi.encodePacked(r, s, v - 27); @@ -338,7 +338,7 @@ contract EIP_712_1014_4337 is BaseTest { }); // Sign user operation. - bytes32 fullHash = SCALibrary.getUserOpFullHash(entryPoint.getUserOpHash(op), toDeployAddress); + bytes32 fullHash = SCALibrary._getUserOpFullHash(entryPoint.getUserOpHash(op), toDeployAddress); op.signature = getSignature(fullHash); // Deposit funds for the transaction. diff --git a/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol b/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol new file mode 100644 index 00000000000..e0ac0036b36 --- /dev/null +++ b/contracts/test/v0.8/foundry/vrf/ChainSpecificUtil.t.sol @@ -0,0 +1,195 @@ +pragma solidity 0.8.6; + +import "../BaseTest.t.sol"; +import {ChainSpecificUtil} from "../../../../src/v0.8/ChainSpecificUtil.sol"; +import {ArbSys} from "../../../../src/v0.8/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {ArbGasInfo} from "../../../../src/v0.8/vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../../../src/v0.8/vendor/@eth-optimism/contracts/v0.8.6/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; + +contract ChainSpecificUtilTest is BaseTest { + // ------------ Start Arbitrum Constants ------------ + + /// @dev ARBSYS_ADDR is the address of the ArbSys precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbSys.sol#L10 + address private constant ARBSYS_ADDR = address(0x0000000000000000000000000000000000000064); + ArbSys private constant ARBSYS = ArbSys(ARBSYS_ADDR); + + /// @dev ARBGAS_ADDR is the address of the ArbGasInfo precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbGasInfo.sol#L10 + address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); + ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); + + uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; + uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; + uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; + + // ------------ End Arbitrum Constants ------------ + + // ------------ Start Optimism Constants ------------ + /// @dev L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + /// @dev OVM_GASPRICEORACLE_ADDR is the address of the OVM_GasPriceOracle precompile on Optimism. + /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR); + + uint256 private constant OP_MAINNET_CHAIN_ID = 10; + uint256 private constant OP_GOERLI_CHAIN_ID = 420; + uint256 private constant OP_SEPOLIA_CHAIN_ID = 11155420; + + /// @dev Base is a OP stack based rollup and follows the same L1 pricing logic as Optimism. + uint256 private constant BASE_MAINNET_CHAIN_ID = 8453; + uint256 private constant BASE_GOERLI_CHAIN_ID = 84531; + + // ------------ End Optimism Constants ------------ + + function setUp() public override { + BaseTest.setUp(); + vm.clearMockedCalls(); + } + + function testGetBlockhashArbitrum() public { + uint256[3] memory chainIds = [ARB_MAINNET_CHAIN_ID, ARB_GOERLI_TESTNET_CHAIN_ID, ARB_SEPOLIA_TESTNET_CHAIN_ID]; + bytes32[3] memory expectedBlockHashes = [keccak256("mainnet"), keccak256("goerli"), keccak256("sepolia")]; + uint256[3] memory expectedBlockNumbers = [uint256(10), 11, 12]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + bytes32 expectedBlockHash = expectedBlockHashes[i]; + uint256 expectedBlockNumber = expectedBlockNumbers[i]; + vm.mockCall( + ARBSYS_ADDR, + abi.encodeWithSelector(ArbSys.arbBlockNumber.selector), + abi.encode(expectedBlockNumber + 1) + ); + vm.mockCall( + ARBSYS_ADDR, + abi.encodeWithSelector(ArbSys.arbBlockHash.selector, expectedBlockNumber), + abi.encodePacked(expectedBlockHash) + ); + bytes32 actualBlockHash = ChainSpecificUtil._getBlockhash(uint64(expectedBlockNumber)); + assertEq(expectedBlockHash, actualBlockHash, "incorrect blockhash"); + } + } + + function testGetBlockhashOptimism() public { + // Optimism L2 block hash is simply blockhash() + bytes32 actualBlockhash = ChainSpecificUtil._getBlockhash(uint64(block.number - 1)); + assertEq(blockhash(block.number - 1), actualBlockhash); + } + + function testGetBlockNumberArbitrum() public { + uint256[2] memory chainIds = [ARB_MAINNET_CHAIN_ID, ARB_GOERLI_TESTNET_CHAIN_ID]; + uint256[3] memory expectedBlockNumbers = [uint256(10), 11, 12]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + uint256 expectedBlockNumber = expectedBlockNumbers[i]; + vm.mockCall(ARBSYS_ADDR, abi.encodeWithSelector(ArbSys.arbBlockNumber.selector), abi.encode(expectedBlockNumber)); + uint256 actualBlockNumber = ChainSpecificUtil._getBlockNumber(); + assertEq(expectedBlockNumber, actualBlockNumber, "incorrect block number"); + } + } + + function testGetBlockNumberOptimism() public { + // Optimism L2 block number is simply block.number + uint256 actualBlockNumber = ChainSpecificUtil._getBlockNumber(); + assertEq(block.number, actualBlockNumber); + } + + function testGetCurrentTxL1GasFeesArbitrum() public { + uint256[3] memory chainIds = [ARB_MAINNET_CHAIN_ID, ARB_GOERLI_TESTNET_CHAIN_ID, ARB_SEPOLIA_TESTNET_CHAIN_ID]; + uint256[3] memory expectedGasFees = [uint256(10 gwei), 12 gwei, 14 gwei]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + uint256 expectedGasFee = expectedGasFees[i]; + vm.mockCall( + ARBGAS_ADDR, + abi.encodeWithSelector(ArbGasInfo.getCurrentTxL1GasFees.selector), + abi.encode(expectedGasFee) + ); + uint256 actualGasFee = ChainSpecificUtil._getCurrentTxL1GasFees(""); + assertEq(expectedGasFee, actualGasFee, "incorrect gas fees"); + } + } + + function testGetCurrentTxL1GasFeesOptimism() public { + // set optimism chain id + uint256[5] memory chainIds = [ + OP_MAINNET_CHAIN_ID, + OP_GOERLI_CHAIN_ID, + OP_SEPOLIA_CHAIN_ID, + BASE_MAINNET_CHAIN_ID, + BASE_GOERLI_CHAIN_ID + ]; + uint256[5] memory expectedGasFees = [uint256(10 gwei), 12 gwei, 14 gwei, 16 gwei, 18 gwei]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + uint256 expectedL1Fee = expectedGasFees[i]; + bytes memory someCalldata = abi.encode(address(0), "blah", uint256(1)); + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(OVM_GasPriceOracle.getL1Fee.selector, bytes.concat(someCalldata, L1_FEE_DATA_PADDING)), + abi.encode(expectedL1Fee) + ); + uint256 actualL1Fee = ChainSpecificUtil._getCurrentTxL1GasFees(someCalldata); + assertEq(expectedL1Fee, actualL1Fee, "incorrect gas fees"); + } + } + + function testGetL1CalldataGasCostArbitrum() public { + uint256[3] memory chainIds = [ARB_MAINNET_CHAIN_ID, ARB_GOERLI_TESTNET_CHAIN_ID, ARB_SEPOLIA_TESTNET_CHAIN_ID]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + vm.mockCall( + ARBGAS_ADDR, + abi.encodeWithSelector(ArbGasInfo.getPricesInWei.selector), + abi.encode(0, 10, 0, 0, 0, 0) + ); + + // fee = l1PricePerByte * (calldataSizeBytes + 140) + // fee = 10 * (10 + 140) = 1500 + uint256 dataFee = ChainSpecificUtil._getL1CalldataGasCost(10); + assertEq(dataFee, 1500); + } + } + + function testGetL1CalldataGasCostOptimism() public { + uint256[5] memory chainIds = [ + OP_MAINNET_CHAIN_ID, + OP_GOERLI_CHAIN_ID, + OP_SEPOLIA_CHAIN_ID, + BASE_MAINNET_CHAIN_ID, + BASE_GOERLI_CHAIN_ID + ]; + for (uint256 i = 0; i < chainIds.length; i++) { + vm.chainId(chainIds[i]); + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(bytes4(hex"519b4bd3")), // l1BaseFee() + abi.encode(10) + ); + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(bytes4(hex"0c18c162")), // overhead() + abi.encode(160) + ); + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(bytes4(hex"f45e65d8")), // scalar() + abi.encode(500_000) + ); + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(bytes4(hex"313ce567")), // decimals() + abi.encode(6) + ); + + // tx_data_gas = count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16 + // tx_data_gas = 0 * 4 + 10 * 16 = 160 + // l1_data_fee = l1_gas_price * (tx_data_gas + fixed_overhead) * dynamic_overhead + // l1_data_fee = 10 * (160 + 160) * 500_000 / 1_000_000 = 1600 + uint256 dataFee = ChainSpecificUtil._getL1CalldataGasCost(10); + assertEq(dataFee, 1600); + } + } +} diff --git a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol index 47fff7ea900..4f3ea40d828 100644 --- a/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol +++ b/contracts/test/v0.8/foundry/vrf/TrustedBlockhashStore.t.sol @@ -1,7 +1,7 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {TrustedBlockhashStore} from "../../../../src/v0.8/dev/vrf/TrustedBlockhashStore.sol"; +import {TrustedBlockhashStore} from "../../../../src/v0.8/vrf/dev/TrustedBlockhashStore.sol"; import {console} from "forge-std/console.sol"; contract TrustedBlockhashStoreTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol index dd607f2ce7b..6378d40167b 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Mock.t.sol @@ -4,7 +4,7 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/mocks/VRFCoordinatorV2Mock.sol"; +import {VRFCoordinatorV2Mock} from "../../../../src/v0.8/vrf/mocks/VRFCoordinatorV2Mock.sol"; import {VRFConsumerV2} from "../../../../src/v0.8/vrf/testhelpers/VRFConsumerV2.sol"; contract VRFCoordinatorV2MockTest is BaseTest { diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol index a847bd5beee..d7a54d6223c 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol @@ -1,14 +1,14 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {VRFV2PlusMaliciousMigrator} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusMaliciousMigrator.sol"; +import {VRFV2PlusMaliciousMigrator} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusMaliciousMigrator.sol"; contract VRFCoordinatorV2Plus_Migration is BaseTest { uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 LINK diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol index 13d52b676c5..e2734f17288 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol @@ -4,12 +4,12 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; -import {BlockhashStore} from "../../../../src/v0.8/dev/BlockhashStore.sol"; -import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusConsumerExample.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {BlockhashStore} from "../../../../src/v0.8/vrf/dev/BlockhashStore.sol"; +import {VRFV2PlusConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusConsumerExample.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; import {console} from "forge-std/console.sol"; import {VmSafe} from "forge-std/Vm.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; // for Math.ceilDiv @@ -282,15 +282,15 @@ contract VRFV2Plus is BaseTest { // Store the previous block's blockhash, and assert that it is as expected. vm.roll(requestBlock + 1); s_bhs.store(requestBlock); - assertEq(hex"c65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8", s_bhs.getBlockhash(requestBlock)); + assertEq(hex"000000000000000000000000000000000000000000000000000000000000000a", s_bhs.getBlockhash(requestBlock)); // Fulfill the request. // Proof generated via the generate-proof-v2-plus script command. Example usage: /* go run . generate-proof-v2-plus \ -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ - -pre-seed 53391429126065232382402681707515137895470547057819816488254124798726362946635 \ - -block-hash 0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8 \ + -pre-seed 93724884573574303181157854277074121673523280784530506403108144933983063023487 \ + -block-hash 0x000000000000000000000000000000000000000000000000000000000000000a \ -block-num 10 \ -sender 0x90A8820424CC8a819d14cBdE54D12fD3fbFa9bb2 \ -native-payment true @@ -301,22 +301,22 @@ contract VRFV2Plus is BaseTest { 62070622898698443831883535403436258712770888294397026493185421712108624767191 ], gamma: [ - 2973102176083872659982988645522968133664529102555885971868619302367987919116, - 43610558806647181042154132372309425100765955827430056035281841579494767100593 + 51111463251706978184511913295560024261167135799300172382907308330135472647507, + 41885656274025752055847945432737871864088659248922821023734315208027501951872 ], - c: 44558436621153210954487996771157467729629491520915192177070584116261579650304, - s: 18447217702001910909971999949841419857536434117467121546901211519652998560328, - seed: 53391429126065232382402681707515137895470547057819816488254124798726362946635, - uWitness: 0x61e70839187C12Fe136bdcC78D1D3765BecA245d, + c: 96917856581077810363012153828220232197567408835708926581335248000925197916153, + s: 103298896676233752268329042222773891728807677368628421408380318882272184455566, + seed: 93724884573574303181157854277074121673523280784530506403108144933983063023487, + uWitness: 0xFCaA10875C6692f6CcC86c64300eb0b52f2D4323, cGammaWitness: [ - 57868024672571504735938309170346165090467827794150592801232968679608710558443, - 19249635816589941728350586356475545703589085434839461964712223344491075318152 + 61463607927970680172418313129927007099021056249775757132623753443657677198526, + 48686021866486086188742596461341782400160109177829661164208082534005682984658 ], sHashWitness: [ - 61151023867440095994162103308586528914977848168432699421313437043942463394142, - 107161674609768447269383119603000260750848712436031813376573304048979100187696 + 91508089836242281395929619352465003226819385335975246221498243754781593857533, + 63571625936444669399167157725633389238098818902162172059681813608664564703308 ], - zInv: 92231836131549905872346812799402691650433126386650679876913933650318463342041 + zInv: 97568175302326019383632009699686265453584842953005404815285123863099260038246 }); VRFCoordinatorV2_5.RequestCommitment memory rc = VRFCoordinatorV2_5.RequestCommitment({ blockNum: requestBlock, @@ -399,15 +399,15 @@ contract VRFV2Plus is BaseTest { // Store the previous block's blockhash, and assert that it is as expected. vm.roll(requestBlock + 1); s_bhs.store(requestBlock); - assertEq(hex"ce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec", s_bhs.getBlockhash(requestBlock)); + assertEq(hex"0000000000000000000000000000000000000000000000000000000000000014", s_bhs.getBlockhash(requestBlock)); // Fulfill the request. // Proof generated via the generate-proof-v2-plus script command. Example usage: /* go run . generate-proof-v2-plus \ -key-hash 0x9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528 \ - -pre-seed 14817911724325909152780695848148728017190840227899344848185245004944693487904 \ - -block-hash 0xce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec \ + -pre-seed 108233140904510496268355288815996296196427471042093167619305836589216327096601 \ + -block-hash 0x0000000000000000000000000000000000000000000000000000000000000014 \ -block-num 20 \ -sender 0x90A8820424CC8a819d14cBdE54D12fD3fbFa9bb2 */ @@ -417,22 +417,22 @@ contract VRFV2Plus is BaseTest { 62070622898698443831883535403436258712770888294397026493185421712108624767191 ], gamma: [ - 33866404953216897461413961842321788789902210776565180957857448351149268461878, - 115311460432520855364215812517921508651759645277579047898967111537639679255245 + 49785247270467418393187938018746488660500261614113251546613288843777654841004, + 8320717868018488740308781441198484312662094766876176838868269181386589318272 ], - c: 32561838617228634441320154326890637858849550728945663611942735469609183032389, - s: 55806041637816588920133401262818662941786708593795051215322306020699218819370, - seed: 14817911724325909152780695848148728017190840227899344848185245004944693487904, - uWitness: 0x917554f18dB75eac206Ae5366B80c0b6A87b5996, + c: 41596204381278553342984662603150353549780558761307588910860350083645227536604, + s: 81592778991188138734863787790226463602813498664606420860910885269124681994753, + seed: 108233140904510496268355288815996296196427471042093167619305836589216327096601, + uWitness: 0x56920892EE71E624d369dCc8dc63B6878C85Ca70, cGammaWitness: [ - 84076069514674055711740813040098459867759972960517070154541804330775196519927, - 23456142794899412334950030002327578074149212885334118042147040122102091306080 + 28250667431035633903490940933503696927659499415200427260709034207157951953043, + 105660182690338773283351292037478192732977803900032569393220726139772041021018 ], sHashWitness: [ - 67919054534004130885903575144858988177160334233773664996450084407340736891592, - 82934864721844704662104532515068228502043057799129930869203380251475000254135 + 18420263847278540234821121001488166570853056146131705862117248292063859054211, + 15740432967529684573970722302302642068194042971767150190061244675457227502736 ], - zInv: 37397948970756055003892765560695914630264479979131589134478580629419519112029 + zInv: 100579074451139970455673776933943662313989441807178260211316504761358492254052 }); VRFCoordinatorV2_5.RequestCommitment memory rc = VRFCoordinatorV2_5.RequestCommitment({ blockNum: requestBlock, diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol index db9e11e059e..335e64ff7ef 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol @@ -1,8 +1,8 @@ pragma solidity 0.8.6; import "../BaseTest.t.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {SubscriptionAPI} from "../../../../src/v0.8/dev/vrf/SubscriptionAPI.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; // for Strings.toString diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol index 8ed39093821..68e36dfe4cb 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper.t.sol @@ -4,12 +4,12 @@ import "../BaseTest.t.sol"; import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; -import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/testhelpers/ExposedVRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapperConsumerBase.sol"; -import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/dev/vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; -import {VRFCoordinatorV2_5} from "../../../../src/v0.8/dev/vrf/VRFCoordinatorV2_5.sol"; -import {VRFV2PlusWrapper} from "../../../../src/v0.8/dev/vrf/VRFV2PlusWrapper.sol"; -import {VRFV2PlusClient} from "../../../../src/v0.8/dev/vrf/libraries/VRFV2PlusClient.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; import {console} from "forge-std/console.sol"; contract VRFV2PlusWrapperTest is BaseTest { @@ -69,12 +69,17 @@ contract VRFV2PlusWrapperTest is BaseTest { coordinatorGasOverhead, // coordinator gas overhead 0, // premium percentage vrfKeyHash, // keyHash - 10 // max number of words + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 0, // fulfillmentFlatFeeLinkPPM + 0 // fulfillmentFlatFeeNativePPM ); ( , , , + , uint32 _wrapperGasOverhead, uint32 _coordinatorGasOverhead, uint8 _wrapperPremiumPercentage, diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol new file mode 100644 index 00000000000..ae399cc95c7 --- /dev/null +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Wrapper_Migration.t.sol @@ -0,0 +1,358 @@ +pragma solidity 0.8.6; + +import "../BaseTest.t.sol"; +import {VRF} from "../../../../src/v0.8/vrf/VRF.sol"; +import {MockLinkToken} from "../../../../src/v0.8/mocks/MockLinkToken.sol"; +import {MockV3Aggregator} from "../../../../src/v0.8/tests/MockV3Aggregator.sol"; +import {ExposedVRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol"; +import {VRFCoordinatorV2Plus_V2Example} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2Plus_V2Example.sol"; +import {VRFV2PlusWrapperConsumerBase} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapperConsumerBase.sol"; +import {VRFV2PlusWrapperConsumerExample} from "../../../../src/v0.8/vrf/dev/testhelpers/VRFV2PlusWrapperConsumerExample.sol"; +import {SubscriptionAPI} from "../../../../src/v0.8/vrf/dev/SubscriptionAPI.sol"; +import {VRFCoordinatorV2_5} from "../../../../src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol"; +import {VRFV2PlusWrapper} from "../../../../src/v0.8/vrf/dev/VRFV2PlusWrapper.sol"; +import {VRFV2PlusClient} from "../../../../src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol"; + +contract VRFV2PlusWrapperTest is BaseTest { + address internal constant LINK_WHALE = 0xD883a6A1C22fC4AbFE938a5aDF9B2Cc31b1BF18B; + uint256 internal constant DEFAULT_NATIVE_FUNDING = 7 ether; // 7 ETH + uint256 internal constant DEFAULT_LINK_FUNDING = 10 ether; // 10 ETH + bytes32 vrfKeyHash = hex"9f2353bde94264dbc3d554a94cceba2d7d2b4fdce4304d3e09a1fea9fbeb1528"; + uint32 wrapperGasOverhead = 10_000; + uint32 coordinatorGasOverhead = 20_000; + + ExposedVRFCoordinatorV2_5 s_testCoordinator; + MockLinkToken s_linkToken; + MockV3Aggregator s_linkNativeFeed; + VRFV2PlusWrapper s_wrapper; + VRFV2PlusWrapperConsumerExample s_consumer; + + VRFCoordinatorV2Plus_V2Example s_newCoordinator; + + VRFCoordinatorV2_5.FeeConfig basicFeeConfig = + VRFCoordinatorV2_5.FeeConfig({fulfillmentFlatFeeLinkPPM: 0, fulfillmentFlatFeeNativePPM: 0}); + + event CoordinatorRegistered(address coordinatorAddress); + event MigrationCompleted(address newCoordinator, uint256 subId); + event WrapperRequestMade(uint256 indexed requestId, uint256 paid); + + function setUp() public override { + BaseTest.setUp(); + + // Fund our users. + vm.roll(1); + vm.deal(LINK_WHALE, 10_000 ether); + changePrank(LINK_WHALE); + + // Deploy link token and link/native feed. + s_linkToken = new MockLinkToken(); + s_linkNativeFeed = new MockV3Aggregator(18, 500000000000000000); // .5 ETH (good for testing) + + // Deploy coordinator and consumer. + s_testCoordinator = new ExposedVRFCoordinatorV2_5(address(0)); + s_wrapper = new VRFV2PlusWrapper(address(s_linkToken), address(s_linkNativeFeed), address(s_testCoordinator)); + s_consumer = new VRFV2PlusWrapperConsumerExample(address(s_linkToken), address(s_wrapper)); + + // Configure the coordinator. + s_testCoordinator.setLINKAndLINKNativeFeed(address(s_linkToken), address(s_linkNativeFeed)); + setConfigCoordinator(basicFeeConfig); + setConfigWrapper(); + + s_testCoordinator.s_config(); + + // Data structures for Migrateable Wrapper + s_newCoordinator = new VRFCoordinatorV2Plus_V2Example(address(0), address(s_testCoordinator)); + vm.expectEmit( + false, // no first indexed topic + false, // no second indexed topic + false, // no third indexed topic + true // check data (target coordinator address) + ); + address newCoordinatorAddr = address(s_newCoordinator); + emit CoordinatorRegistered(newCoordinatorAddr); + s_testCoordinator.registerMigratableCoordinator(newCoordinatorAddr); + assertTrue(s_testCoordinator.isTargetRegisteredExternal(newCoordinatorAddr)); + } + + function setConfigCoordinator(VRFCoordinatorV2_5.FeeConfig memory feeConfig) internal { + s_testCoordinator.setConfig( + 0, // minRequestConfirmations + 2_500_000, // maxGasLimit + 1, // stalenessSeconds + 50_000, // gasAfterPaymentCalculation + 50000000000000000, // fallbackWeiPerUnitLink + feeConfig + ); + } + + function setConfigWrapper() internal { + s_wrapper.setConfig( + wrapperGasOverhead, // wrapper gas overhead + coordinatorGasOverhead, // coordinator gas overhead + 0, // premium percentage + vrfKeyHash, // keyHash + 10, // max number of words, + 1, // stalenessSeconds + 50000000000000000, // fallbackWeiPerUnitLink + 0, // fulfillmentFlatFeeLinkPPM + 0 // fulfillmentFlatFeeNativePPM + ); + ( + , + , + , + , + uint32 _wrapperGasOverhead, + uint32 _coordinatorGasOverhead, + uint8 _wrapperPremiumPercentage, + bytes32 _keyHash, + uint8 _maxNumWords + ) = s_wrapper.getConfig(); + assertEq(_wrapperGasOverhead, wrapperGasOverhead); + assertEq(_coordinatorGasOverhead, coordinatorGasOverhead); + assertEq(0, _wrapperPremiumPercentage); + assertEq(vrfKeyHash, _keyHash); + assertEq(10, _maxNumWords); + } + + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint256 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + bytes extraArgs, + address indexed sender + ); + + function testMigrateWrapperLINKPayment() public { + s_linkToken.transfer(address(s_consumer), DEFAULT_LINK_FUNDING); + + uint256 subID = s_wrapper.SUBSCRIPTION_ID(); + address oldCoordinatorAddr = address(s_testCoordinator); + + // Fund subscription with native and LINK payment to check + // if funds are transferred to new subscription after call + // migration to new coordinator + s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(subID)); + s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(subID); + + // Get type and version. + assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + + // subscription exists in V1 coordinator before migration + + ( + uint96 balance, + uint96 nativeBalance, + uint64 reqCount, + address owner, + address[] memory consumers + ) = s_testCoordinator.getSubscription(subID); + assertEq(reqCount, 0); + assertEq(balance, DEFAULT_LINK_FUNDING); + assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); + assertEq(owner, address(s_wrapper)); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_wrapper)); + + vm.startPrank(LINK_WHALE); + + // Update wrapper to point to the new coordinator + vm.expectEmit( + false, // no first indexed field + false, // no second indexed field + false, // no third indexed field + true // check data fields + ); + address newCoordinatorAddr = address(s_newCoordinator); + emit MigrationCompleted(newCoordinatorAddr, subID); + + s_wrapper.migrate(newCoordinatorAddr); + + // subscription no longer exists in v1 coordinator after migration + vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); + s_testCoordinator.getSubscription(subID); + assertEq(s_testCoordinator.s_totalBalance(), 0); + assertEq(s_testCoordinator.s_totalNativeBalance(), 0); + assertEq(s_linkToken.balanceOf(oldCoordinatorAddr), 0); + assertEq(oldCoordinatorAddr.balance, 0); + + // subscription exists in v2 coordinator + (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(subID); + assertEq(owner, address(s_wrapper)); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_wrapper)); + assertEq(reqCount, 0); + assertEq(balance, DEFAULT_LINK_FUNDING); + assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); + assertEq(s_newCoordinator.s_totalLinkBalance(), DEFAULT_LINK_FUNDING); + assertEq(s_newCoordinator.s_totalNativeBalance(), DEFAULT_NATIVE_FUNDING); + assertEq(s_linkToken.balanceOf(newCoordinatorAddr), DEFAULT_LINK_FUNDING); + assertEq(newCoordinatorAddr.balance, DEFAULT_NATIVE_FUNDING); + + // calling migrate again on V1 coordinator should fail + vm.expectRevert(); + s_wrapper.migrate(newCoordinatorAddr); + + // Request randomness from wrapper. + uint32 callbackGasLimit = 1_000_000; + vm.expectEmit(true, true, true, true); + uint256 wrapperCost = s_wrapper.calculateRequestPrice(callbackGasLimit); + emit WrapperRequestMade(1, wrapperCost); + uint256 requestId = s_consumer.makeRequest(callbackGasLimit, 0, 1); + assertEq(requestId, 1); + + (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); + uint32 expectedPaid = (callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead) * 2; + uint256 wrapperCostEstimate = s_wrapper.estimateRequestPrice(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPrice(callbackGasLimit); + assertEq(paid, expectedPaid); // 1_030_000 * 2 for link/native ratio + assertEq(uint256(paid), wrapperCostEstimate); + assertEq(wrapperCostEstimate, wrapperCostCalculation); + assertEq(fulfilled, false); + assertEq(native, false); + assertEq(s_linkToken.balanceOf(address(s_consumer)), DEFAULT_LINK_FUNDING - expectedPaid); + + (, uint256 gasLimit, ) = s_wrapper.s_callbacks(requestId); + assertEq(gasLimit, callbackGasLimit); + + vm.stopPrank(); + + vm.startPrank(newCoordinatorAddr); + + uint256[] memory words = new uint256[](1); + words[0] = 123; + s_wrapper.rawFulfillRandomWords(requestId, words); + (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); + assertEq(nowFulfilled, true); + assertEq(storedWords[0], 123); + + vm.stopPrank(); + + /// Withdraw funds from wrapper. + vm.startPrank(LINK_WHALE); + uint256 priorWhaleBalance = s_linkToken.balanceOf(LINK_WHALE); + s_wrapper.withdraw(LINK_WHALE, paid); + assertEq(s_linkToken.balanceOf(LINK_WHALE), priorWhaleBalance + paid); + assertEq(s_linkToken.balanceOf(address(s_wrapper)), 0); + + vm.stopPrank(); + } + + function testMigrateWrapperNativePayment() public { + vm.deal(address(s_consumer), DEFAULT_NATIVE_FUNDING); + + uint256 subID = s_wrapper.SUBSCRIPTION_ID(); + address oldCoordinatorAddr = address(s_testCoordinator); + + // Fund subscription with native and LINK payment to check + // if funds are transferred to new subscription after call + // migration to new coordinator + s_linkToken.transferAndCall(oldCoordinatorAddr, DEFAULT_LINK_FUNDING, abi.encode(subID)); + s_testCoordinator.fundSubscriptionWithNative{value: DEFAULT_NATIVE_FUNDING}(subID); + + // Get type and version. + assertEq(s_wrapper.typeAndVersion(), "VRFV2Wrapper 1.0.0"); + + // subscription exists in V1 coordinator before migration + ( + uint96 balance, + uint96 nativeBalance, + uint64 reqCount, + address owner, + address[] memory consumers + ) = s_testCoordinator.getSubscription(subID); + assertEq(reqCount, 0); + assertEq(balance, DEFAULT_LINK_FUNDING); + assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); + assertEq(owner, address(s_wrapper)); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_wrapper)); + + vm.startPrank(LINK_WHALE); + + // Update wrapper to point to the new coordinator + vm.expectEmit( + false, // no first indexed field + false, // no second indexed field + false, // no third indexed field + true // check data fields + ); + address newCoordinatorAddr = address(s_newCoordinator); + emit MigrationCompleted(newCoordinatorAddr, subID); + + s_wrapper.migrate(newCoordinatorAddr); + + // subscription no longer exists in v1 coordinator after migration + vm.expectRevert(SubscriptionAPI.InvalidSubscription.selector); + s_testCoordinator.getSubscription(subID); + assertEq(s_testCoordinator.s_totalBalance(), 0); + assertEq(s_testCoordinator.s_totalNativeBalance(), 0); + assertEq(s_linkToken.balanceOf(oldCoordinatorAddr), 0); + assertEq(oldCoordinatorAddr.balance, 0); + + // subscription exists in v2 coordinator + (balance, nativeBalance, reqCount, owner, consumers) = s_newCoordinator.getSubscription(subID); + assertEq(owner, address(s_wrapper)); + assertEq(consumers.length, 1); + assertEq(consumers[0], address(s_wrapper)); + assertEq(reqCount, 0); + assertEq(balance, DEFAULT_LINK_FUNDING); + assertEq(nativeBalance, DEFAULT_NATIVE_FUNDING); + assertEq(s_newCoordinator.s_totalLinkBalance(), DEFAULT_LINK_FUNDING); + assertEq(s_newCoordinator.s_totalNativeBalance(), DEFAULT_NATIVE_FUNDING); + assertEq(s_linkToken.balanceOf(newCoordinatorAddr), DEFAULT_LINK_FUNDING); + assertEq(newCoordinatorAddr.balance, DEFAULT_NATIVE_FUNDING); + + // calling migrate again on V1 coordinator should fail + vm.expectRevert(); + s_wrapper.migrate(newCoordinatorAddr); + + // Request randomness from wrapper. + uint32 callbackGasLimit = 1_000_000; + vm.expectEmit(true, true, true, true); + uint256 wrapperCost = s_wrapper.calculateRequestPriceNative(callbackGasLimit); + emit WrapperRequestMade(1, wrapperCost); + uint256 requestId = s_consumer.makeRequestNative(callbackGasLimit, 0, 1); + assertEq(requestId, 1); + + (uint256 paid, bool fulfilled, bool native) = s_consumer.s_requests(requestId); + uint32 expectedPaid = callbackGasLimit + wrapperGasOverhead + coordinatorGasOverhead; + uint256 wrapperNativeCostEstimate = s_wrapper.estimateRequestPriceNative(callbackGasLimit, tx.gasprice); + uint256 wrapperCostCalculation = s_wrapper.calculateRequestPriceNative(callbackGasLimit); + assertEq(paid, expectedPaid); + assertEq(uint256(paid), wrapperNativeCostEstimate); + assertEq(wrapperNativeCostEstimate, wrapperCostCalculation); + assertEq(fulfilled, false); + assertEq(native, true); + assertEq(address(s_consumer).balance, DEFAULT_NATIVE_FUNDING - expectedPaid); + + (, uint256 gasLimit, ) = s_wrapper.s_callbacks(requestId); + assertEq(gasLimit, callbackGasLimit); + + vm.stopPrank(); + + vm.startPrank(newCoordinatorAddr); + + uint256[] memory words = new uint256[](1); + words[0] = 123; + s_wrapper.rawFulfillRandomWords(requestId, words); + (, bool nowFulfilled, uint256[] memory storedWords) = s_consumer.getRequestStatus(requestId); + assertEq(nowFulfilled, true); + assertEq(storedWords[0], 123); + + vm.stopPrank(); + + // Withdraw funds from wrapper. + vm.startPrank(LINK_WHALE); + uint256 priorWhaleBalance = LINK_WHALE.balance; + s_wrapper.withdrawNative(LINK_WHALE, paid); + assertEq(LINK_WHALE.balance, priorWhaleBalance + paid); + assertEq(address(s_wrapper).balance, 0); + + vm.stopPrank(); + } +} diff --git a/contracts/test/v0.8/functions/v0/Functions.test.ts b/contracts/test/v0.8/functions/v0/Functions.test.ts deleted file mode 100644 index 242e5d57aad..00000000000 --- a/contracts/test/v0.8/functions/v0/Functions.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { ethers } from 'hardhat' -import { - publicAbi, - decodeDietCBOR, - hexToBuf, -} from '../../../test-helpers/helpers' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, providers, Signer } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { makeDebug } from '../../../test-helpers/debug' - -const debug = makeDebug('FunctionsTestHelper') -let concreteFunctionsTestHelperFactory: ContractFactory - -let roles: Roles - -before(async () => { - roles = (await getUsers()).roles - concreteFunctionsTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsTestHelper.sol:FunctionsTestHelper', - roles.defaultAccount, - ) -}) - -describe('FunctionsTestHelper', () => { - let ctr: Contract - let defaultAccount: Signer - - beforeEach(async () => { - defaultAccount = roles.defaultAccount - ctr = await concreteFunctionsTestHelperFactory - .connect(defaultAccount) - .deploy() - }) - - it('has a limited public interface [ @skip-coverage ]', () => { - publicAbi(ctr, [ - 'closeEvent', - 'initializeRequestForInlineJavaScript', - 'addSecrets', - 'addTwoArgs', - 'addEmptyArgs', - ]) - }) - - async function parseRequestDataEvent(tx: providers.TransactionResponse) { - const receipt = await tx.wait() - const data = receipt.logs?.[0].data - const d = debug.extend('parseRequestDataEvent') - d('data %s', data) - return ethers.utils.defaultAbiCoder.decode(['bytes'], data ?? '') - } - - describe('#closeEvent', () => { - it('handles empty request', async () => { - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: '', - }, - ) - }) - }) - - describe('#initializeRequestForInlineJavaScript', () => { - it('emits simple CBOR encoded request for js', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - }, - ) - }) - }) - - describe('#initializeRequestForInlineJavaScript to revert', () => { - it('reverts with EmptySource() if source param is empty', async () => { - await expect( - ctr.initializeRequestForInlineJavaScript(''), - ).to.be.revertedWith('EmptySource()') - }) - }) - - describe('#addSecrets', () => { - it('emits CBOR encoded request with js and secrets', async () => { - const js = 'function run(args, responses) {}' - const secrets = '0xA161616162' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addSecrets(secrets) - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - secretsLocation: decoded.secretsLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - secretsLocation: 1, - secrets: hexToBuf(secrets), - }, - ) - }) - }) - - describe('#addSecrets to revert', () => { - it('reverts with EmptySecrets() if secrets param is empty', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await expect(ctr.addSecrets('0x')).to.be.revertedWith('EmptySecrets()') - }) - }) - - describe('#addArgs', () => { - it('emits CBOR encoded request with js and args', async () => { - const js = 'function run(args, responses) {}' - await ctr.initializeRequestForInlineJavaScript(js) - await ctr.addTwoArgs('arg1', 'arg2') - const tx = await ctr.closeEvent() - const [payload] = await parseRequestDataEvent(tx) - const decoded = await decodeDietCBOR(payload) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - args: ['arg1', 'arg2'], - }, - ) - }) - }) - - describe('#addEmptyArgs to revert', () => { - it('reverts with EmptyArgs() if args param is empty', async () => { - await expect(ctr.addEmptyArgs()).to.be.revertedWith('EmptyArgs()') - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/FunctionsBillingRegistry.test.ts b/contracts/test/v0.8/functions/v0/FunctionsBillingRegistry.test.ts deleted file mode 100644 index 95160689d28..00000000000 --- a/contracts/test/v0.8/functions/v0/FunctionsBillingRegistry.test.ts +++ /dev/null @@ -1,834 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { BigNumber, Contract, ContractFactory, Signer } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { randomAddressString } from 'hardhat/internal/hardhat-network/provider/utils/random' -import { stringToBytes } from '../../../test-helpers/helpers' - -let functionsOracleFactory: ContractFactory -let clientTestHelperFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles -let subOwner: Signer -let subOwnerAddress: string -let consumer: Signer -let consumerAddress: string -let stranger: Signer -let strangerAddress: string - -const stringToHex = (s: string) => { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(s)) -} - -const encodeReport = (requestId: string, result: string, err: string) => { - const abi = ethers.utils.defaultAbiCoder - return abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[requestId], [result], [err]], - ) -} - -const linkEth = BigNumber.from(5021530000000000) - -type RegistryConfig = { - maxGasLimit: number - stalenessSeconds: number - gasAfterPaymentCalculation: number - weiPerUnitLink: BigNumber - gasOverhead: number - requestTimeoutSeconds: number -} -const config: RegistryConfig = { - maxGasLimit: 1_000_000, - stalenessSeconds: 86_400, - gasAfterPaymentCalculation: - 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315, - weiPerUnitLink: BigNumber.from('5000000000000000'), - gasOverhead: 100_000, - requestTimeoutSeconds: 300, -} - -before(async () => { - roles = (await getUsers()).roles - - functionsOracleFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol:FunctionsOracleHelper', - roles.defaultAccount, - ) - - clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.consumer, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol:FunctionsBillingRegistryWithInit', - roles.consumer, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -describe('FunctionsRegistry', () => { - let registry: Contract - let oracle: Contract - let client: Contract - let linkToken: Contract - let mockLinkEth: Contract - - beforeEach(async () => { - const { roles } = await getUsers() - subOwner = roles.consumer - subOwnerAddress = await subOwner.getAddress() - consumer = roles.consumer2 - consumerAddress = await consumer.getAddress() - stranger = roles.stranger - strangerAddress = await stranger.getAddress() - - // Deploy - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy(0, linkEth) - oracle = await functionsOracleFactory.connect(roles.defaultAccount).deploy() - registry = await functionsBillingRegistryFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, mockLinkEth.address, oracle.address) - client = await clientTestHelperFactory - .connect(roles.consumer) - .deploy(oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - - // Setup accounts - await linkToken.transfer( - subOwnerAddress, - BigNumber.from('1000000000000000000'), // 1 LINK - ) - await linkToken.transfer( - strangerAddress, - BigNumber.from('1000000000000000000'), // 1 LINK - ) - }) - - // NOTE: Temporarily disabled until contract size can be reduced in another way - // describe('General', () => { - // it('#typeAndVersion', async () => { - // expect(await registry.callStatic.typeAndVersion()).to.be.equal( - // 'FunctionsBillingRegistry 0.0.0', - // ) - // }) - // }) - - describe('Config', () => { - it('non-owner is unable set config', async () => { - await expect( - registry - .connect(roles.stranger) - .setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ), - ).to.be.revertedWith('OnlyCallableByOwner()') - }) - - it('owner can set config', async () => { - await expect( - registry - .connect(roles.defaultAccount) - .setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ), - ).not.to.be.reverted - }) - - it('returns the config set on the registry', async () => { - await registry - .connect(roles.defaultAccount) - .setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - const [ - maxGasLimit, - stalenessSeconds, - gasAfterPaymentCalculation, - weiPerUnitLink, - gasOverhead, - ] = await registry.connect(roles.stranger).getConfig() - - await expect(config.maxGasLimit).to.equal(maxGasLimit) - await expect(config.stalenessSeconds).to.equal(stalenessSeconds) - await expect(config.gasAfterPaymentCalculation).to.equal( - gasAfterPaymentCalculation, - ) - await expect(config.weiPerUnitLink).to.equal(weiPerUnitLink) - await expect(config.gasOverhead).to.equal(gasOverhead) - }) - }) - - describe('DON registration', () => { - it('non-owner is unable to register a DON', async () => { - await expect( - registry.connect(roles.stranger).setAuthorizedSenders([oracle.address]), - ).to.be.revertedWith('OnlyCallableByOwner()') - }) - - it('owner can register a DON', async () => { - await expect( - registry - .connect(roles.defaultAccount) - .setAuthorizedSenders([oracle.address]), - ).not.to.be.reverted - }) - }) - - async function createSubscription( - owner: Signer, - consumers: string[], - ): Promise { - const tx = await registry.connect(owner).createSubscription() - const receipt = await tx.wait() - const subId = receipt.events[0].args['subscriptionId'].toNumber() - for (let i = 0; i < consumers.length; i++) { - await registry.connect(owner).addConsumer(subId, consumers[i]) - } - return subId - } - - describe('Subscription management', () => { - describe('#createSubscription', async function () { - it('can create a subscription', async function () { - await expect(registry.connect(subOwner).createSubscription()) - .to.emit(registry, 'SubscriptionCreated') - .withArgs(1, subOwnerAddress) - const s = await registry.getSubscription(1) - expect(s.balance.toString() == '0', 'invalid balance') - expect(s.owner == subOwnerAddress, 'invalid address') - }) - it('subscription id increments', async function () { - await expect(registry.connect(subOwner).createSubscription()) - .to.emit(registry, 'SubscriptionCreated') - .withArgs(1, subOwnerAddress) - await expect(registry.connect(subOwner).createSubscription()) - .to.emit(registry, 'SubscriptionCreated') - .withArgs(2, subOwnerAddress) - }) - it('cannot create more than the max', async function () { - const subId = createSubscription(subOwner, []) - for (let i = 0; i < 100; i++) { - await registry - .connect(subOwner) - .addConsumer(subId, randomAddressString()) - } - await expect( - registry.connect(subOwner).addConsumer(subId, randomAddressString()), - ).to.be.revertedWith(`TooManyConsumers()`) - }) - }) - - describe('#requestSubscriptionOwnerTransfer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - it('rejects non-owner', async function () { - await expect( - registry - .connect(roles.stranger) - .requestSubscriptionOwnerTransfer(subId, strangerAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) - }) - it('owner can request transfer', async function () { - await expect( - registry - .connect(subOwner) - .requestSubscriptionOwnerTransfer(subId, strangerAddress), - ) - .to.emit(registry, 'SubscriptionOwnerTransferRequested') - .withArgs(subId, subOwnerAddress, strangerAddress) - // Same request is a noop - await expect( - registry - .connect(subOwner) - .requestSubscriptionOwnerTransfer(subId, strangerAddress), - ).to.not.emit(registry, 'SubscriptionOwnerTransferRequested') - }) - }) - - describe('#acceptSubscriptionOwnerTransfer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - it('subscription must exist', async function () { - await expect( - registry - .connect(subOwner) - .acceptSubscriptionOwnerTransfer(1203123123), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be requested owner to accept', async function () { - await expect( - registry - .connect(subOwner) - .requestSubscriptionOwnerTransfer(subId, strangerAddress), - ) - await expect( - registry.connect(subOwner).acceptSubscriptionOwnerTransfer(subId), - ).to.be.revertedWith(`MustBeRequestedOwner("${strangerAddress}")`) - }) - it('requested owner can accept', async function () { - await expect( - registry - .connect(subOwner) - .requestSubscriptionOwnerTransfer(subId, strangerAddress), - ) - .to.emit(registry, 'SubscriptionOwnerTransferRequested') - .withArgs(subId, subOwnerAddress, strangerAddress) - await expect( - registry.connect(stranger).acceptSubscriptionOwnerTransfer(subId), - ) - .to.emit(registry, 'SubscriptionOwnerTransferred') - .withArgs(subId, subOwnerAddress, strangerAddress) - }) - }) - - describe('#addConsumer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - it('subscription must exist', async function () { - await expect( - registry.connect(subOwner).addConsumer(1203123123, strangerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - registry.connect(stranger).addConsumer(subId, strangerAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) - }) - it('add is idempotent', async function () { - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - }) - it('cannot add more than maximum', async function () { - // There is one consumer, add another 99 to hit the max - for (let i = 0; i < 99; i++) { - await registry - .connect(subOwner) - .addConsumer(subId, randomAddressString()) - } - // Adding one more should fail - // await registry.connect(subOwner).addConsumer(subId, strangerAddress); - await expect( - registry.connect(subOwner).addConsumer(subId, strangerAddress), - ).to.be.revertedWith(`TooManyConsumers()`) - // Same is true if we first create with the maximum - const consumers: string[] = [] - for (let i = 0; i < 100; i++) { - consumers.push(randomAddressString()) - } - subId = await createSubscription(subOwner, consumers) - await expect( - registry.connect(subOwner).addConsumer(subId, strangerAddress), - ).to.be.revertedWith(`TooManyConsumers()`) - }) - it('owner can update', async function () { - await expect( - registry.connect(subOwner).addConsumer(subId, strangerAddress), - ) - .to.emit(registry, 'SubscriptionConsumerAdded') - .withArgs(subId, strangerAddress) - }) - }) - - describe('#removeConsumer', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - it('subscription must exist', async function () { - await expect( - registry - .connect(subOwner) - .removeConsumer(1203123123, strangerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - registry.connect(stranger).removeConsumer(subId, strangerAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) - }) - it('owner can update', async function () { - const subBefore = await registry.getSubscription(subId) - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - await expect( - registry.connect(subOwner).removeConsumer(subId, strangerAddress), - ) - .to.emit(registry, 'SubscriptionConsumerRemoved') - .withArgs(subId, strangerAddress) - const subAfter = await registry.getSubscription(subId) - // Subscription should NOT contain the removed consumer - expect(subBefore.consumers).to.deep.equal(subAfter.consumers) - }) - it('can remove all consumers', async function () { - // Testing the handling of zero. - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - await registry.connect(subOwner).removeConsumer(subId, strangerAddress) - await registry.connect(subOwner).removeConsumer(subId, consumerAddress) - // Should be empty - const subAfter = await registry.getSubscription(subId) - expect(subAfter.consumers).to.deep.equal([]) - }) - }) - - describe('#pendingRequestExists', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('130790416713017745'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, client.address) - await registry.connect(roles.defaultAccount).reg - await registry.setAuthorizedSenders([oracle.address]) - }) - it('returns false when there is no latest pending request', async function () { - expect(await registry.connect(subOwner).pendingRequestExists(subId)).to - .be.false - }) - it('returns true when the latest request is pending', async function () { - await client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId) - expect(await registry.connect(subOwner).pendingRequestExists(subId)).to - .be.true - }) - }) - - describe('#cancelSubscription', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - it('subscription must exist', async function () { - await expect( - registry - .connect(subOwner) - .cancelSubscription(1203123123, subOwnerAddress), - ).to.be.revertedWith(`InvalidSubscription`) - }) - it('must be owner', async function () { - await expect( - registry.connect(stranger).cancelSubscription(subId, subOwnerAddress), - ).to.be.revertedWith(`MustBeSubOwner("${subOwnerAddress}")`) - }) - it('can cancel', async function () { - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('1000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await expect( - registry.connect(subOwner).cancelSubscription(subId, strangerAddress), - ) - .to.emit(registry, 'SubscriptionCanceled') - .withArgs(subId, strangerAddress, BigNumber.from('1000')) - const strangerBalance = await linkToken.balanceOf(strangerAddress) - expect(strangerBalance.toString()).to.equal('1000000000000001000') - await expect( - registry.connect(subOwner).getSubscription(subId), - ).to.be.revertedWith('InvalidSubscription') - }) - it('can add same consumer after canceling', async function () { - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('1000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - await registry - .connect(subOwner) - .cancelSubscription(subId, strangerAddress) - subId = await createSubscription(subOwner, [consumerAddress]) - // The cancel should have removed this consumer, so we can add it again. - await registry.connect(subOwner).addConsumer(subId, strangerAddress) - }) - it('cannot cancel with pending request', async function () { - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('130790416713017745'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, client.address) - await registry.connect(roles.defaultAccount).reg - await registry.setAuthorizedSenders([oracle.address]) - await client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId) - // Should revert with outstanding requests - await expect( - registry.connect(subOwner).cancelSubscription(subId, strangerAddress), - ).to.be.revertedWith('PendingRequestExists()') - // However the owner is able to cancel - // funds go to the sub owner. - await expect( - registry.connect(roles.defaultAccount).ownerCancelSubscription(subId), - ) - .to.emit(registry, 'SubscriptionCanceled') - .withArgs( - subId, - subOwnerAddress, - BigNumber.from('130790416713017745'), - ) - }) - }) - - describe('#recoverFunds', async function () { - let subId: number - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - }) - - it('function that should change internal balance do', async function () { - type bf = [() => Promise, BigNumber] - const balanceChangingFns: Array = [ - [ - async function () { - const s = ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]) - await linkToken - .connect(subOwner) - .transferAndCall(registry.address, BigNumber.from('1000'), s) - }, - BigNumber.from('1000'), - ], - [ - async function () { - await registry - .connect(subOwner) - .cancelSubscription(subId, strangerAddress) - }, - BigNumber.from('-1000'), - ], - ] - for (const [fn, expectedBalanceChange] of balanceChangingFns) { - const startingBalance = await registry.getTotalBalance() - await fn() - const endingBalance = await registry.getTotalBalance() - expect( - endingBalance.sub(startingBalance).toString() == - expectedBalanceChange.toString(), - ) - } - }) - it('only owner can recover', async function () { - await expect( - registry.connect(subOwner).recoverFunds(strangerAddress), - ).to.be.revertedWith('OnlyCallableByOwner()') - }) - - it('owner can recover link transferred', async function () { - // Set the internal balance - expect(BigNumber.from('0'), linkToken.balanceOf(strangerAddress)) - const s = ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]) - await linkToken - .connect(subOwner) - .transferAndCall(registry.address, BigNumber.from('1000'), s) - // Circumvent internal balance - await linkToken - .connect(subOwner) - .transfer(registry.address, BigNumber.from('1000')) - // Should recover this 1000 - await expect( - registry.connect(roles.defaultAccount).recoverFunds(strangerAddress), - ) - .to.emit(registry, 'FundsRecovered') - .withArgs(strangerAddress, BigNumber.from('1000')) - expect(BigNumber.from('1000'), linkToken.balanceOf(strangerAddress)) - }) - }) - }) - - describe('#startBilling', () => { - let subId: number - - beforeEach(async () => { - await registry.setAuthorizedSenders([oracle.address]) - - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - subId = await createSubscription(subOwner, [consumerAddress]) - - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('54666805176129187'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, client.address) - await registry.connect(roles.defaultAccount).reg - }) - - it('only callable by registered DONs', async () => { - await expect( - registry.connect(consumer).startBilling(stringToHex('some data'), { - requester: consumerAddress, - client: consumerAddress, - subscriptionId: subId, - gasPrice: 20_000, - gasLimit: 20_000, - confirmations: 50, - }), - ).to.be.revertedWith(`reverted with custom error 'UnauthorizedSender()'`) - }) - - it('a subscription can only be used by a subscription consumer', async () => { - await expect( - oracle - .connect(stranger) - .sendRequest(subId, stringToBytes('some data'), 0), - ).to.be.revertedWith( - `reverted with custom error 'InvalidConsumer(${subId}, "${strangerAddress}")`, - ) - await expect( - client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId), - ).to.not.be.reverted - }) - - it('fails if the subscription does not have the funds for the estimated cost', async () => { - const subId = await createSubscription(subOwner, [subOwnerAddress]) - await registry.connect(subOwner).addConsumer(subId, client.address) - - await expect( - client - .connect(subOwner) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId), - ).to.be.revertedWith(`InsufficientBalance()`) - }) - - it('when successful, emits an event', async () => { - await expect( - client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId), - ).to.emit(registry, 'BillingStart') - }) - - it('fails multiple requests if the subscription does not have the funds for the estimated cost', async () => { - client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId, { - gasPrice: 1000000008, - }) - - await expect( - client - .connect(subOwner) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId, { - gasPrice: 1000000008, - }), - ).to.be.revertedWith(`InsufficientBalance()`) - }) - }) - - describe('#fulfillAndBill', () => { - let subId: number - let requestId: string - - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('1000000000000000000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, client.address) - await registry.connect(roles.defaultAccount).reg - await registry.setAuthorizedSenders([oracle.address]) - - const request = await client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId) - requestId = (await request.wait()).events[3].args[0] - }) - - it('only callable by registered DONs', async () => { - const someAddress = randomAddressString() - const someSigners = Array(31).fill(ethers.constants.AddressZero) - someSigners[0] = someAddress - await expect( - registry - .connect(consumer) - .fulfillAndBill( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('some data'), - stringToHex('some data'), - someAddress, - someSigners, - 1, - 10, - 0, - ), - ).to.be.revertedWith('UnauthorizedSender()') - }) - - it('when successful, emits an event', async () => { - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - ) - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(registry, 'BillingEnd') - }) - - it('validates request ID', async () => { - const unknown = - '0x67c6a2e151d4352a55021b5d0028c18121cfc24c7d73b179d22b17eeeeeeeeee' - const report = encodeReport( - ethers.utils.hexZeroPad(unknown, 32), - stringToHex('hello world'), - stringToHex(''), - ) - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(oracle, 'InvalidRequestID') - }) - - it('pays the transmitter the expected amount', async () => { - const oracleBalanceBefore = await linkToken.balanceOf( - await roles.oracleNode.getAddress(), - ) - const [subscriptionBalanceBefore] = await registry.getSubscription(subId) - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - ) - - const transmitter = await roles.oracleNode.getAddress() - - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ) - .to.emit(oracle, 'OracleResponse') - .withArgs(requestId) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, transmitter) - .to.emit(registry, 'BillingEnd') - .to.emit(client, 'FulfillRequestInvoked') - - await registry - .connect(roles.oracleNode) - .oracleWithdraw( - await roles.oracleNode.getAddress(), - BigNumber.from('0'), - ) - - const oracleBalanceAfter = await linkToken.balanceOf( - await roles.oracleNode.getAddress(), - ) - const [subscriptionBalanceAfter] = await registry.getSubscription(subId) - - expect(subscriptionBalanceBefore.gt(subscriptionBalanceAfter)).to.be.true - expect(oracleBalanceAfter.gt(oracleBalanceBefore)).to.be.true - expect(subscriptionBalanceBefore.sub(subscriptionBalanceAfter)).to.equal( - oracleBalanceAfter.sub(oracleBalanceBefore), - ) - }) - }) - - describe('#oracleWithdraw', async function () { - it('cannot withdraw with no balance', async function () { - await expect( - registry - .connect(roles.oracleNode) - .oracleWithdraw(randomAddressString(), BigNumber.from('100')), - ).to.be.revertedWith(`InsufficientBalance`) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/FunctionsBillingRegistryUpgradeable.test.ts b/contracts/test/v0.8/functions/v0/FunctionsBillingRegistryUpgradeable.test.ts deleted file mode 100644 index 5de99864525..00000000000 --- a/contracts/test/v0.8/functions/v0/FunctionsBillingRegistryUpgradeable.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { ethers, upgrades } from 'hardhat' -import { expect } from 'chai' -import { BigNumber, Contract, ContractFactory, Signer } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' - -let functionsOracleFactory: ContractFactory -let clientTestHelperFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles -let subOwner: Signer -let subOwnerAddress: string -let consumer: Signer -let consumerAddress: string -let stranger: Signer -let strangerAddress: string - -const stringToHex = (s: string) => { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(s)) -} - -const encodeReport = (requestId: string, result: string, err: string) => { - const abi = ethers.utils.defaultAbiCoder - return abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[requestId], [result], [err]], - ) -} - -const fundedLink = '1000000000000000000' -const linkEth = BigNumber.from(5021530000000000) - -type RegistryConfig = { - maxGasLimit: number - stalenessSeconds: number - gasAfterPaymentCalculation: number - weiPerUnitLink: BigNumber - gasOverhead: number - requestTimeoutSeconds: number -} -const config: RegistryConfig = { - maxGasLimit: 1_000_000, - stalenessSeconds: 86_400, - gasAfterPaymentCalculation: - 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315, - weiPerUnitLink: BigNumber.from('5000000000000000'), - gasOverhead: 100_000, - requestTimeoutSeconds: 300, -} - -before(async () => { - roles = (await getUsers()).roles - - functionsOracleFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol:FunctionsOracleHelper', - roles.defaultAccount, - ) - - clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.consumer, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryOriginal.sol:FunctionsBillingRegistryOriginal', - roles.consumer, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -describe('FunctionsRegistryUpgradeable', () => { - let registry: Contract - let oracle: Contract - let client: Contract - let linkToken: Contract - let mockLinkEth: Contract - - beforeEach(async () => { - const { roles } = await getUsers() - subOwner = roles.consumer - subOwnerAddress = await subOwner.getAddress() - consumer = roles.consumer2 - consumerAddress = await consumer.getAddress() - stranger = roles.stranger - strangerAddress = await stranger.getAddress() - - // Deploy - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy(0, linkEth) - oracle = await functionsOracleFactory.connect(roles.defaultAccount).deploy() - registry = await upgrades.deployProxy( - functionsBillingRegistryFactory.connect(roles.defaultAccount), - [linkToken.address, mockLinkEth.address, oracle.address], - ) - client = await clientTestHelperFactory - .connect(roles.consumer) - .deploy(oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - - // Setup accounts - await linkToken.transfer( - subOwnerAddress, - BigNumber.from(fundedLink), // 1 LINK - ) - await linkToken.transfer( - strangerAddress, - BigNumber.from(fundedLink), // 1 LINK - ) - }) - - async function createSubscription( - owner: Signer, - consumers: string[], - ): Promise { - const tx = await registry.connect(owner).createSubscription() - const receipt = await tx.wait() - const subId = receipt.events[0].args['subscriptionId'].toNumber() - for (let i = 0; i < consumers.length; i++) { - await registry.connect(owner).addConsumer(subId, consumers[i]) - } - return subId - } - - describe('Upgrades', () => { - let subId: number - let requestId: string - - async function migrateAndCheck(factoryPath: string): Promise { - // Upgrade the implementation contract a new version - const functionsBillingRegistryMigrationFactory = - await ethers.getContractFactory(factoryPath, roles.consumer) - - const upgradedRegistry = await upgrades.upgradeProxy( - registry.address, - functionsBillingRegistryMigrationFactory.connect(roles.defaultAccount), - ) - - // Check config is the same - const currentConfig = await upgradedRegistry.getConfig() - expect(currentConfig.maxGasLimit).to.equal(config.maxGasLimit) - expect(currentConfig.stalenessSeconds).to.equal(config.stalenessSeconds) - expect(currentConfig.gasAfterPaymentCalculation).to.equal( - config.gasAfterPaymentCalculation, - ) - expect(currentConfig.fallbackWeiPerUnitLink).to.equal( - config.weiPerUnitLink, - ) - expect(currentConfig.gasOverhead).to.equal(config.gasOverhead) - - // Check funds are the same - const subscription = await upgradedRegistry.getSubscription(subId) - expect(subscription.balance).to.equal(fundedLink) - - // Check request fulfillment still works - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - ) - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(registry, 'BillingEnd') - - return upgradedRegistry - } - - beforeEach(async () => { - subId = await createSubscription(subOwner, [consumerAddress]) - - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - await linkToken - .connect(subOwner) - .transferAndCall( - registry.address, - BigNumber.from('1000000000000000000'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subId]), - ) - await registry.connect(subOwner).addConsumer(subId, client.address) - await registry.connect(roles.defaultAccount).reg - await registry.setAuthorizedSenders([oracle.address]) - - const request = await client - .connect(consumer) - .sendSimpleRequestWithJavaScript(`return 'hello world'`, subId) - requestId = (await request.wait()).events[3].args[0] - }) - - it('is successful when deployed behind a proxy', async () => { - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - ) - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(registry, 'BillingEnd') - }) - - it('can be upgraded to a new implementation', async () => { - const upgradedRegistry = await migrateAndCheck( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/mocks/FunctionsBillingRegistryMigration.sol:FunctionsBillingRegistryMigration', - ) - - // Check that upgrade was successful - const dummyRequest = [ - '0x', - { - subscriptionId: subId, - client: client.address, - gasLimit: 0, - gasPrice: 0, - }, - ] - const registryFee = await upgradedRegistry.getRequiredFee(...dummyRequest) - expect(registryFee).to.equal(1) - }) - - it('can be upgraded to the latest implementation', async () => { - await migrateAndCheck( - 'src/v0.8/functions/dev/v0_0_0/FunctionsBillingRegistry.sol:FunctionsBillingRegistry', - ) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/FunctionsClient.test.ts b/contracts/test/v0.8/functions/v0/FunctionsClient.test.ts deleted file mode 100644 index 94b06d8b37e..00000000000 --- a/contracts/test/v0.8/functions/v0/FunctionsClient.test.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { ethers } from 'hardhat' -import { assert, expect } from 'chai' -import { Contract, ContractFactory, providers } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { decodeDietCBOR, stringToBytes } from '../../../test-helpers/helpers' - -let concreteFunctionsClientFactory: ContractFactory -let functionsOracleFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles - -function getEventArg(events: any, eventName: string, argIndex: number) { - if (Array.isArray(events)) { - const event = events.find((e: any) => e.event == eventName) - if (event && Array.isArray(event.args) && event.args.length > 0) { - return event.args[argIndex] - } - } - return undefined -} - -async function parseOracleRequestEventArgs(tx: providers.TransactionResponse) { - const receipt = await tx.wait() - const data = receipt.logs?.[1].data - return ethers.utils.defaultAbiCoder.decode( - ['address', 'address', 'uint64', 'address', 'bytes'], - data ?? '', - ) -} - -before(async () => { - roles = (await getUsers()).roles - - concreteFunctionsClientFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.defaultAccount, - ) - functionsOracleFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol:FunctionsOracleHelper', - roles.defaultAccount, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol:FunctionsBillingRegistryWithInit', - roles.defaultAccount, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -describe('FunctionsClientTestHelper', () => { - const donPublicKey = - '0x3804a19f2437f7bba4fcfbc194379e43e514aa98073db3528ccdbdb642e24011' - let subscriptionId: number - const anyValue = () => true - - let client: Contract - let oracle: Contract - let registry: Contract - let linkToken: Contract - let mockLinkEth: Contract - - beforeEach(async () => { - // Deploy - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy( - 0, - ethers.BigNumber.from(5021530000000000), - ) - oracle = await functionsOracleFactory.connect(roles.defaultAccount).deploy() - registry = await functionsBillingRegistryFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, mockLinkEth.address, oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - client = await concreteFunctionsClientFactory - .connect(roles.defaultAccount) - .deploy(oracle.address) - await registry.setAuthorizedSenders([oracle.address]) - - await registry.setConfig( - 1_000_000, - 86_400, - 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315, - ethers.BigNumber.from('5000000000000000'), - 100_000, - 300, - ) - - // Setup accounts - const createSubTx = await registry - .connect(roles.defaultAccount) - .createSubscription() - const receipt = await createSubTx.wait() - subscriptionId = receipt.events[0].args['subscriptionId'].toNumber() - - await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, client.address) - - await linkToken - .connect(roles.defaultAccount) - .transferAndCall( - registry.address, - ethers.BigNumber.from('115957983815660167'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - }) - - describe('#getDONPublicKey', () => { - it('returns DON public key set on Oracle', async () => { - await expect(oracle.setDONPublicKey(donPublicKey)).not.to.be.reverted - expect(await client.callStatic.getDONPublicKey()).to.be.equal( - donPublicKey, - ) - }) - }) - - describe('#sendSimpleRequestWithJavaScript', () => { - it('emits events from the client and the oracle contracts', async () => { - await expect( - client - .connect(roles.defaultAccount) - .sendSimpleRequestWithJavaScript('function run() {}', subscriptionId), - ) - .to.emit(client, 'RequestSent') - .withArgs(anyValue) - .to.emit(oracle, 'OracleRequest') - .withArgs( - anyValue, - client.address, - await roles.defaultAccount.getAddress(), - subscriptionId, - await roles.defaultAccount.getAddress(), - anyValue, - ) - }) - - it('encodes user request to CBOR', async () => { - const js = 'function run() {}' - const tx = await client.sendSimpleRequestWithJavaScript( - js, - subscriptionId, - ) - const args = await parseOracleRequestEventArgs(tx) - assert.equal(5, args.length) - const decoded = await decodeDietCBOR(args[4]) - assert.deepEqual( - { - ...decoded, - language: decoded.language.toNumber(), - codeLocation: decoded.codeLocation.toNumber(), - }, - { - language: 0, - codeLocation: 0, - source: js, - }, - ) - }) - }) - - describe('#fulfillRequest', () => { - it('emits fulfillment events', async () => { - const tx = await client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ) - - const { events } = await tx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(tx).to.emit(client, 'RequestSent').withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const abi = ethers.utils.defaultAbiCoder - - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[ethers.utils.hexZeroPad(requestId, 32)], [response], [error]], - ) - - await expect(oracle.callReport(report, { gasLimit: 300_000 })) - .to.emit(oracle, 'OracleResponse') - .withArgs(requestId) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, anyValue) - .to.emit(registry, 'BillingEnd') - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId, response, error) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts b/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts deleted file mode 100644 index 397cc3b397f..00000000000 --- a/contracts/test/v0.8/functions/v0/FunctionsOracle.test.ts +++ /dev/null @@ -1,537 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { BigNumber, Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' - -let functionsOracleFactory: ContractFactory -let clientTestHelperFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles - -const stringToHex = (s: string) => { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(s)) -} - -const anyValue = () => true - -const encodeReport = (requestId: string, result: string, err: string) => { - const abi = ethers.utils.defaultAbiCoder - return abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[requestId], [result], [err]], - ) -} - -before(async () => { - roles = (await getUsers()).roles - - functionsOracleFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol:FunctionsOracleHelper', - roles.defaultAccount, - ) - - clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.consumer, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol:FunctionsBillingRegistryWithInit', - roles.defaultAccount, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -describe('FunctionsOracle', () => { - let subscriptionId: number - const donPublicKey = - '0x3804a19f2437f7bba4fcfbc194379e43e514aa98073db3528ccdbdb642e24011' - let client: Contract - let oracle: Contract - let registry: Contract - let linkToken: Contract - let mockLinkEth: Contract - let transmitters: string[] - - beforeEach(async () => { - // Deploy contracts - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy( - 0, - ethers.BigNumber.from(5021530000000000), - ) - oracle = await functionsOracleFactory.connect(roles.defaultAccount).deploy() - registry = await functionsBillingRegistryFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, mockLinkEth.address, oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - client = await clientTestHelperFactory - .connect(roles.defaultAccount) - .deploy(oracle.address) - await registry.setAuthorizedSenders([oracle.address]) - - await registry.setConfig( - 1_000_000, // maxGasLimit - 86_400, // stalenessSeconds - 39_173 /* gasAfterPaymentCalculation - gathered by taking the difference from gasleft() directly after payment calculation, and then again after the BillingEnd event, using a hardhat console log - */, - ethers.BigNumber.from('5000000000000000'), // fallbackWeiPerUnitLink - 519_719 /* gasOverhead - gathered by taking the difference from initialGas and gasleft() directly after payment calculation, adding back the user's callback gas usage, using a hardhat console log - NOTE: this number can vary slightly by number of nodes on the DON - */, - 300, // requestTimeoutSeconds - ) - - // Setup accounts - const createSubTx = await registry - .connect(roles.defaultAccount) - .createSubscription() - const receipt = await createSubTx.wait() - subscriptionId = receipt.events[0].args['subscriptionId'].toNumber() - - await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, await roles.defaultAccount.getAddress()) - - await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, client.address) - - await linkToken - .connect(roles.defaultAccount) - .transferAndCall( - registry.address, - ethers.BigNumber.from('300938394174049741'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - - const signers = Array.from( - [0, 0, 0, 0], - (_) => ethers.Wallet.createRandom().address, - ) - transmitters = [ - await roles.oracleNode1.getAddress(), - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - await roles.oracleNode4.getAddress(), - ] - await oracle.setConfig(signers, transmitters, 1, [], 1, []) - }) - - describe('General', () => { - it('#typeAndVersion', async () => { - expect(await oracle.callStatic.typeAndVersion()).to.be.equal( - 'FunctionsOracle 0.0.0', - ) - }) - - it('returns DON public key set on this Oracle', async () => { - await expect(oracle.setDONPublicKey(donPublicKey)).not.to.be.reverted - expect(await oracle.callStatic.getDONPublicKey()).to.be.equal( - donPublicKey, - ) - }) - - it('reverts setDONPublicKey for empty data', async () => { - const emptyPublicKey = stringToHex('') - await expect(oracle.setDONPublicKey(emptyPublicKey)).to.be.revertedWith( - 'EmptyPublicKey', - ) - }) - - async function validatePubKeys( - expectedNodes: string[], - expectedKeys: string[], - ) { - const allNodesAndKeys = await oracle.getAllNodePublicKeys() - for (let i = 0; i < expectedNodes.length; i++) { - expect(allNodesAndKeys[0][i]).to.be.equal(expectedNodes[i]) - expect(allNodesAndKeys[1][i]).to.be.equal(expectedKeys[i]) - } - } - - it('set/delete/get node public keys', async () => { - const emptyKey = stringToHex('') - const publicKey2 = stringToHex('key420') - const publicKey3 = stringToHex('key666') - - await oracle.setNodePublicKey(roles.oracleNode2.getAddress(), publicKey2) - await oracle.setNodePublicKey(roles.oracleNode3.getAddress(), publicKey3) - validatePubKeys(transmitters, [ - emptyKey, - publicKey2, - publicKey3, - emptyKey, - ]) - - await oracle.deleteNodePublicKey(roles.oracleNode1.getAddress()) - await oracle.deleteNodePublicKey(roles.oracleNode2.getAddress()) - validatePubKeys(transmitters, [emptyKey, emptyKey, publicKey3, emptyKey]) - }) - - it('reverts setNodePublicKey for unauthorized callers', async () => { - const pubKey = stringToHex('abcd') - - await expect( - oracle - .connect(roles.defaultAccount) - .setNodePublicKey(roles.oracleNode2.getAddress(), pubKey), - ).not.to.be.reverted - - await expect( - oracle - .connect(roles.consumer) - .setNodePublicKey(roles.oracleNode2.getAddress(), pubKey), - ).to.be.revertedWith('UnauthorizedPublicKeyChange') - - await expect( - oracle - .connect(roles.consumer) - .setNodePublicKey(roles.consumer.getAddress(), pubKey), - ).to.be.revertedWith('UnauthorizedPublicKeyChange') - - await expect( - oracle - .connect(roles.oracleNode2) - .setNodePublicKey(roles.oracleNode3.getAddress(), pubKey), - ).to.be.revertedWith('UnauthorizedPublicKeyChange') - - await expect( - oracle - .connect(roles.oracleNode2) - .setNodePublicKey(roles.oracleNode2.getAddress(), pubKey), - ).not.to.be.reverted - }) - - it('reverts deleteNodePublicKey for unauthorized callers', async () => { - await expect( - oracle - .connect(roles.defaultAccount) - .deleteNodePublicKey(roles.oracleNode2.getAddress()), - ).not.to.be.reverted - - await expect( - oracle - .connect(roles.consumer) - .deleteNodePublicKey(roles.oracleNode2.getAddress()), - ).to.be.revertedWith('UnauthorizedPublicKeyChange') - - await expect( - oracle - .connect(roles.consumer) - .deleteNodePublicKey(roles.consumer.getAddress()), - ).not.to.be.reverted - }) - }) - - describe('Sending requests', () => { - it('#sendRequest emits OracleRequest event', async () => { - const data = stringToHex('some data') - await expect(oracle.sendRequest(subscriptionId, data, 0)) - .to.emit(oracle, 'OracleRequest') - .withArgs( - anyValue, - await roles.defaultAccount.getAddress(), - await roles.defaultAccount.getAddress(), - subscriptionId, - await roles.defaultAccount.getAddress(), - data, - ) - }) - - it('#sendRequest reverts for empty data', async () => { - const data = stringToHex('') - await expect( - oracle.sendRequest(subscriptionId, data, 0), - ).to.be.revertedWith('EmptyRequestData') - }) - - it('#sendRequest returns non-empty requestId', async () => { - const data = stringToHex('test data') - const requestId = await oracle.callStatic.sendRequest( - subscriptionId, - data, - 0, - ) - expect(requestId).not.to.be.empty - }) - - it('#sendRequest returns different requestIds', async () => { - const data = stringToHex('test data') - const requestId1 = await oracle.callStatic.sendRequest( - subscriptionId, - data, - 0, - ) - await expect(oracle.sendRequest(subscriptionId, data, 0)) - .to.emit(oracle, 'OracleRequest') - .withArgs( - anyValue, - await roles.defaultAccount.getAddress(), - await roles.defaultAccount.getAddress(), - subscriptionId, - await roles.defaultAccount.getAddress(), - data, - ) - const requestId2 = await oracle.callStatic.sendRequest( - subscriptionId, - data, - 0, - ) - expect(requestId1).not.to.be.equal(requestId2) - }) - }) - - describe('Fulfilling requests', () => { - const placeTestRequest = async () => { - const requestId = await client - .connect(roles.oracleNode) - .callStatic.sendSimpleRequestWithJavaScript( - 'function(){}', - subscriptionId, - ) - await expect( - client - .connect(roles.oracleNode) - .sendSimpleRequestWithJavaScript('function(){}', subscriptionId), - ) - .to.emit(client, 'RequestSent') - .withArgs(requestId) - return requestId - } - - it('#fulfillRequest emits an error for unknown requestId', async () => { - const requestId = - '0x67c6a2e151d4352a55021b5d0028c18121cfc24c7d73b179d22b17daff069c6e' - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex(''), - ) - - await expect(oracle.callReport(report)).to.emit( - oracle, - 'InvalidRequestID', - ) - }) - - it('#fulfillRequest emits OracleResponse and ResponseTransmitted', async () => { - const requestId = await placeTestRequest() - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex(''), - ) - - const transmitter = await roles.oracleNode.getAddress() - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'OracleResponse') - .withArgs(requestId) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, transmitter) - }) - - it('#estimateCost correctly estimates cost [ @skip-coverage ]', async () => { - const [subscriptionBalanceBefore] = - await registry.getSubscription(subscriptionId) - - const request = await client - .connect(roles.oracleNode) - .sendSimpleRequestWithJavaScript('function(){}', subscriptionId) - const receipt = await request.wait() - const requestId = receipt.events[3].args[0] - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex(''), - ) - - const transmitter = await roles.oracleNode.getAddress() - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'OracleResponse') - .withArgs(requestId) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, transmitter) - .to.emit(registry, 'BillingEnd') - - const [subscriptionBalanceAfter] = - await registry.getSubscription(subscriptionId) - - const feeData = await ethers.provider.getFeeData() - const estimatedCost = await client.estimateJuelCost( - 'function(){}', - subscriptionId, - feeData.gasPrice ?? BigNumber.from(0), - ) - // Expect charged amount to be +-0.01% - expect( - subscriptionBalanceBefore.sub(subscriptionBalanceAfter), - ).to.be.below(estimatedCost.add(estimatedCost.div(100))) - expect( - subscriptionBalanceBefore.sub(subscriptionBalanceAfter), - ).to.be.above(estimatedCost.sub(estimatedCost.div(100))) - }) - - it('#fulfillRequest emits UserCallbackError if callback reverts', async () => { - const requestId = await placeTestRequest() - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex(''), - ) - - const transmitter = await roles.oracleNode.getAddress() - - await client.setRevertFulfillRequest(true) - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'UserCallbackError') - .withArgs(requestId, anyValue) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, transmitter) - }) - - it('#fulfillRequest emits UserCallbackError if callback does invalid op', async () => { - const requestId = await placeTestRequest() - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex(''), - ) - - const transmitter = await roles.oracleNode.getAddress() - - await client.setDoInvalidOperation(true) - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'UserCallbackError') - .withArgs(requestId, anyValue) - .to.emit(oracle, 'ResponseTransmitted') - .withArgs(requestId, transmitter) - }) - - it('#fulfillRequest invokes client fulfillRequest', async () => { - const requestId = await placeTestRequest() - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex('err'), - ) - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId, stringToHex('response'), stringToHex('err')) - }) - - it('#fulfillRequest invalidates requestId', async () => { - const requestId = await placeTestRequest() - - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('response'), - stringToHex('err'), - ) - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId, stringToHex('response'), stringToHex('err')) - - // for second fulfill the requestId becomes invalid - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'InvalidRequestID') - .withArgs(requestId) - }) - - it('#_report reverts for inconsistent encoding', async () => { - const requestId = await placeTestRequest() - - const abi = ethers.utils.defaultAbiCoder - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[requestId], [], []], - ) - - await expect( - oracle.connect(roles.oracleNode).callReport(report), - ).to.be.revertedWith('ReportInvalid()') - }) - - it('#_report handles multiple reports', async () => { - const requestId1 = await placeTestRequest() - const requestId2 = await placeTestRequest() - const result1 = stringToHex('result1') - const result2 = stringToHex('result2') - const err = stringToHex('') - - const abi = ethers.utils.defaultAbiCoder - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [ - [requestId1, requestId2], - [result1, result2], - [err, err], - ], - ) - - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 300_000 }), - ) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId1, result1, err) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId2, result2, err) - }) - - it('#_report handles multiple failures', async () => { - const requestId1 = await placeTestRequest() - const requestId2 = await placeTestRequest() - const result1 = stringToHex('result1') - const result2 = stringToHex('result2') - const err = stringToHex('') - - const abi = ethers.utils.defaultAbiCoder - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [ - [requestId1, requestId2], - [result1, result2], - [err, err], - ], - ) - - await client.setRevertFulfillRequest(true) - - await expect(oracle.connect(roles.oracleNode).callReport(report)) - .to.emit(oracle, 'UserCallbackError') - .withArgs(requestId1, anyValue) - .to.emit(oracle, 'UserCallbackError') - .withArgs(requestId2, anyValue) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/FunctionsOracleUpgradeable.test.ts b/contracts/test/v0.8/functions/v0/FunctionsOracleUpgradeable.test.ts deleted file mode 100644 index fe2dfdc9c3e..00000000000 --- a/contracts/test/v0.8/functions/v0/FunctionsOracleUpgradeable.test.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { ethers, upgrades } from 'hardhat' -import { expect } from 'chai' -import { BigNumber, Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' - -let functionsOracleOriginalFactory: ContractFactory -let clientTestHelperFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles - -const stringToHex = (s: string) => { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(s)) -} - -const encodeReport = (requestId: string, result: string, err: string) => { - const abi = ethers.utils.defaultAbiCoder - return abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[requestId], [result], [err]], - ) -} - -type RegistryConfig = { - maxGasLimit: number - stalenessSeconds: number - gasAfterPaymentCalculation: number - weiPerUnitLink: BigNumber - gasOverhead: number - requestTimeoutSeconds: number -} -const config: RegistryConfig = { - maxGasLimit: 1_000_000, - stalenessSeconds: 86_400, - gasAfterPaymentCalculation: - 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315, - weiPerUnitLink: BigNumber.from('5000000000000000'), - gasOverhead: 100_000, - requestTimeoutSeconds: 300, -} - -before(async () => { - roles = (await getUsers()).roles - - functionsOracleOriginalFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleOriginalHelper.sol:FunctionsOracleOriginalHelper', - roles.defaultAccount, - ) - - clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.consumer, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol:FunctionsBillingRegistryWithInit', - roles.defaultAccount, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -describe('FunctionsOracleUpgradeable', () => { - let subscriptionId: number - let client: Contract - let oracle: Contract - let registry: Contract - let linkToken: Contract - let mockLinkEth: Contract - let transmitters: string[] - - beforeEach(async () => { - // Deploy contracts - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy( - 0, - ethers.BigNumber.from(5021530000000000), - ) - oracle = await upgrades.deployProxy( - functionsOracleOriginalFactory.connect(roles.defaultAccount), - ) - registry = await functionsBillingRegistryFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, mockLinkEth.address, oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - client = await clientTestHelperFactory - .connect(roles.defaultAccount) - .deploy(oracle.address) - await registry.setAuthorizedSenders([oracle.address]) - - await registry.setConfig( - config.maxGasLimit, - config.stalenessSeconds, - config.gasAfterPaymentCalculation, - config.weiPerUnitLink, - config.gasOverhead, - config.requestTimeoutSeconds, - ) - - // Setup accounts - const createSubTx = await registry - .connect(roles.defaultAccount) - .createSubscription() - const receipt = await createSubTx.wait() - subscriptionId = receipt.events[0].args['subscriptionId'].toNumber() - - await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, await roles.defaultAccount.getAddress()) - - await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, client.address) - - await linkToken - .connect(roles.defaultAccount) - .transferAndCall( - registry.address, - ethers.BigNumber.from('300938394174049741'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - - const signers = Array.from( - [0, 0, 0, 0], - (_) => ethers.Wallet.createRandom().address, - ) - transmitters = [ - await roles.oracleNode1.getAddress(), - await roles.oracleNode2.getAddress(), - await roles.oracleNode3.getAddress(), - await roles.oracleNode4.getAddress(), - ] - await oracle.setConfig(signers, transmitters, 1, [], 1, []) - }) - - describe('Upgrades', () => { - const placeTestRequest = async () => { - const requestId = await client - .connect(roles.oracleNode) - .callStatic.sendSimpleRequestWithJavaScript( - 'function(){}', - subscriptionId, - ) - await expect( - client - .connect(roles.oracleNode) - .sendSimpleRequestWithJavaScript('function(){}', subscriptionId), - ) - .to.emit(client, 'RequestSent') - .withArgs(requestId) - return requestId - } - - async function migrateAndCheck(factoryPath: string): Promise { - const functionsOracleMigrationFactory = await ethers.getContractFactory( - factoryPath, - roles.consumer, - ) - - // Upgrade the implementation contract - const upgradedOracle = await upgrades.upgradeProxy( - oracle.address, - functionsOracleMigrationFactory.connect(roles.defaultAccount), - ) - - // Check request fulfillment still works - const requestId = await placeTestRequest() - const report = encodeReport( - ethers.utils.hexZeroPad(requestId, 32), - stringToHex('hello world'), - stringToHex(''), - ) - await expect( - upgradedOracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 500_000 }), - ).to.emit(registry, 'BillingEnd') - - return upgradedOracle - } - - it('is successful when deployed behind a proxy', async () => { - const requestId1 = await placeTestRequest() - const requestId2 = await placeTestRequest() - const result1 = stringToHex('result1') - const result2 = stringToHex('result2') - const err = stringToHex('') - - const abi = ethers.utils.defaultAbiCoder - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [ - [requestId1, requestId2], - [result1, result2], - [err, err], - ], - ) - - await expect( - oracle - .connect(roles.oracleNode) - .callReport(report, { gasLimit: 300_000 }), - ) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId1, result1, err) - .to.emit(client, 'FulfillRequestInvoked') - .withArgs(requestId2, result2, err) - }) - - it('can be upgraded to a new implementation', async () => { - const upgradedOracle = await migrateAndCheck( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleMigrationHelper.sol:FunctionsOracleMigrationHelper', - ) - - // Check that upgrade was successful - const dummyRequest = [ - '0x', - { - subscriptionId, - client: client.address, - gasLimit: 0, - gasPrice: 0, - }, - ] - const registryFee = await upgradedOracle.getRequiredFee(...dummyRequest) - expect(registryFee).to.equal(1) - }) - - it('can be upgraded to the latest implementation', async () => { - await migrateAndCheck( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleUpgradeableHelper.sol:FunctionsOracleUpgradeableHelper', - ) - }) - }) -}) diff --git a/contracts/test/v0.8/functions/v0/Gas.test.ts b/contracts/test/v0.8/functions/v0/Gas.test.ts deleted file mode 100644 index affa8052b9f..00000000000 --- a/contracts/test/v0.8/functions/v0/Gas.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { ethers } from 'hardhat' -import { expect } from 'chai' -import { Contract, ContractFactory } from 'ethers' -import { Roles, getUsers } from '../../../test-helpers/setup' -import { stringToBytes } from '../../../test-helpers/helpers' - -let concreteFunctionsClientFactory: ContractFactory -let functionsOracleFactory: ContractFactory -let functionsBillingRegistryFactory: ContractFactory -let linkTokenFactory: ContractFactory -let mockAggregatorV3Factory: ContractFactory -let roles: Roles - -function getEventArg(events: any, eventName: string, argIndex: number) { - if (Array.isArray(events)) { - const event = events.find((e: any) => e.event == eventName) - if (event && Array.isArray(event.args) && event.args.length > 0) { - return event.args[argIndex] - } - } - return undefined -} - -const baselineGasUsed = 641560 -let currentGasUsed = 0 - -before(async () => { - roles = (await getUsers()).roles - - concreteFunctionsClientFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', - roles.defaultAccount, - ) - functionsOracleFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsOracleHelper.sol:FunctionsOracleHelper', - roles.defaultAccount, - ) - - functionsBillingRegistryFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v0_0_0/testhelpers/FunctionsBillingRegistryWithInit.sol:FunctionsBillingRegistryWithInit', - roles.defaultAccount, - ) - - linkTokenFactory = await ethers.getContractFactory( - 'src/v0.8/mocks/MockLinkToken.sol:MockLinkToken', - roles.consumer, - ) - - mockAggregatorV3Factory = await ethers.getContractFactory( - 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', - roles.consumer, - ) -}) - -after(() => { - const score = currentGasUsed - baselineGasUsed - console.log( - `\n ⛳ Baseline gas used : ${baselineGasUsed} gas`, - ) - console.log(`\n Current gas used : ${currentGasUsed} gas`) - console.log(`\n 🚩 Delta : ${score} gas`) -}) - -let subscriptionId: number - -let client: Contract -let oracle: Contract -let registry: Contract -let linkToken: Contract -let mockLinkEth: Contract - -beforeEach(async () => { - // Deploy - linkToken = await linkTokenFactory.connect(roles.defaultAccount).deploy() - mockLinkEth = await mockAggregatorV3Factory.deploy( - 0, - ethers.BigNumber.from(5021530000000000), - ) - oracle = await functionsOracleFactory.connect(roles.defaultAccount).deploy() - registry = await functionsBillingRegistryFactory - .connect(roles.defaultAccount) - .deploy(linkToken.address, mockLinkEth.address, oracle.address) - - // Setup contracts - await oracle.setRegistry(registry.address) - await oracle.deactivateAuthorizedReceiver() - client = await concreteFunctionsClientFactory - .connect(roles.defaultAccount) - .deploy(oracle.address) - await registry.setAuthorizedSenders([oracle.address]) - - await registry.setConfig( - 1_000_000, - 86_400, - 21_000 + 5_000 + 2_100 + 20_000 + 2 * 2_100 - 15_000 + 7_315, - ethers.BigNumber.from('5000000000000000'), - 100_000, - 300, - ) -}) - -describe('Gas', () => { - it('uses the expected amount of gas', async () => { - // Setup accounts - const createSubTx = await registry - .connect(roles.defaultAccount) - .createSubscription() - const createSubscriptionTxReceipt = await createSubTx.wait() - subscriptionId = - createSubscriptionTxReceipt.events[0].args['subscriptionId'].toNumber() - const createSubscriptionGasUsed = createSubscriptionTxReceipt.gasUsed - - const addConsumerTx = await registry - .connect(roles.defaultAccount) - .addConsumer(subscriptionId, client.address) - const { gasUsed: addConsumerTxGasUsed } = await addConsumerTx.wait() - - const transferAndCallTx = await linkToken - .connect(roles.defaultAccount) - .transferAndCall( - registry.address, - ethers.BigNumber.from('115957983815660167'), - ethers.utils.defaultAbiCoder.encode(['uint64'], [subscriptionId]), - ) - const { gasUsed: transferAndCallTxGasUsed } = await transferAndCallTx.wait() - - const requestTx = await client.sendSimpleRequestWithJavaScript( - 'function run(){return response}', - subscriptionId, - ) - - const { events, gasUsed: requestTxGasUsed } = await requestTx.wait() - const requestId = getEventArg(events, 'RequestSent', 0) - await expect(requestTx).to.emit(client, 'RequestSent').withArgs(requestId) - - const response = stringToBytes('response') - const error = stringToBytes('') - const abi = ethers.utils.defaultAbiCoder - - const report = abi.encode( - ['bytes32[]', 'bytes[]', 'bytes[]'], - [[ethers.utils.hexZeroPad(requestId, 32)], [response], [error]], - ) - - const fulfillmentTx = await oracle.callReport(report, { - gasLimit: 300_000, - }) - - const { gasUsed: fulfillmentTxGasUsed } = await fulfillmentTx.wait() - - currentGasUsed = createSubscriptionGasUsed - .add(addConsumerTxGasUsed) - .add(transferAndCallTxGasUsed) - .add(requestTxGasUsed) - .add(fulfillmentTxGasUsed) - .toNumber() - }) -}) diff --git a/contracts/test/v0.8/functions/v1/Functions.test.ts b/contracts/test/v0.8/functions/v1/Functions.test.ts index 4de281c0b74..14a68c211b9 100644 --- a/contracts/test/v0.8/functions/v1/Functions.test.ts +++ b/contracts/test/v0.8/functions/v1/Functions.test.ts @@ -17,7 +17,7 @@ let roles: Roles before(async () => { roles = (await getUsers()).roles concreteFunctionsTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsTestHelper.sol:FunctionsTestHelper', + 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsTestHelper.sol:FunctionsTestHelper', roles.defaultAccount, ) }) diff --git a/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts b/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts index dad78769b75..826953fb2c4 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsClient.test.ts @@ -178,7 +178,7 @@ describe('Faulty Functions Client', () => { it('can complete requests with an empty callback', async () => { const clientWithEmptyCallbackTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientWithEmptyCallback.sol:FunctionsClientWithEmptyCallback', + 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientWithEmptyCallback.sol:FunctionsClientWithEmptyCallback', roles.consumer, ) diff --git a/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts b/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts index 5aece579b66..89444ca8661 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsCoordinator.test.ts @@ -51,7 +51,7 @@ describe('Functions Coordinator', () => { it('#fulfillmentGasPriceOverEstimationBP overestimates gas cost', async () => { const estimateWithNoOverestimaton = - await contracts.coordinator.estimateCost(1, 0x0, 100_000, 20) + await contracts.coordinator.estimateCost(1, 0x0, 100_000, 2000000000) await contracts.coordinator.updateConfig({ ...coordinatorConfig, @@ -60,7 +60,7 @@ describe('Functions Coordinator', () => { // Halve the gas price, which should be the same estimate because of fulfillmentGasPriceOverEstimationBP doubling the gas price const estimateWithOverestimaton = - await contracts.coordinator.estimateCost(1, 0x0, 100_000, 10) + await contracts.coordinator.estimateCost(1, 0x0, 100_000, 1000000000) expect(estimateWithNoOverestimaton).to.equal(estimateWithOverestimaton) }) diff --git a/contracts/test/v0.8/functions/v1/utils.ts b/contracts/test/v0.8/functions/v1/utils.ts index 98f6143dee3..b91905b9448 100644 --- a/contracts/test/v0.8/functions/v1/utils.ts +++ b/contracts/test/v0.8/functions/v1/utils.ts @@ -52,7 +52,7 @@ export const encodeReport = async ( offchainMetadata: string, ) => { const functionsResponse = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_0_0/FunctionsCoordinator.sol:FunctionsCoordinator', + 'src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol:FunctionsCoordinator', ) const onchainMetadataBytes = functionsResponse.interface._abiCoder.encode( [ @@ -98,6 +98,7 @@ export type CoordinatorConfig = { maxSupportedRequestDataVersion: number fulfillmentGasPriceOverEstimationBP: number fallbackNativePerUnitLink: BigNumber + minimumEstimateGasPriceWei: number } const fallbackNativePerUnitLink = 5000000000000000 export const coordinatorConfig: CoordinatorConfig = { @@ -109,6 +110,7 @@ export const coordinatorConfig: CoordinatorConfig = { maxSupportedRequestDataVersion: 1, fulfillmentGasPriceOverEstimationBP: 0, fallbackNativePerUnitLink: BigNumber.from(fallbackNativePerUnitLink), + minimumEstimateGasPriceWei: 1000000000, } export const accessControlMockPublicKey = ethers.utils.getAddress( '0x32237412cC0321f56422d206e505dB4B3871AF5c', @@ -130,19 +132,19 @@ export async function setupRolesAndFactories(): Promise<{ }> { const roles = (await getUsers()).roles const functionsRouterFactory = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_0_0/FunctionsRouter.sol:FunctionsRouter', + 'src/v0.8/functions/dev/v1_X/FunctionsRouter.sol:FunctionsRouter', roles.defaultAccount, ) const functionsCoordinatorFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsCoordinatorTestHelper.sol:FunctionsCoordinatorTestHelper', + 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol:FunctionsCoordinatorTestHelper', roles.defaultAccount, ) const accessControlFactory = await ethers.getContractFactory( - 'src/v0.8/functions/dev/v1_0_0/accessControl/TermsOfServiceAllowList.sol:TermsOfServiceAllowList', + 'src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol:TermsOfServiceAllowList', roles.defaultAccount, ) const clientTestHelperFactory = await ethers.getContractFactory( - 'src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', + 'src/v0.8/functions/tests/v1_X/testhelpers/FunctionsClientTestHelper.sol:FunctionsClientTestHelper', roles.consumer, ) const linkTokenFactory = await ethers.getContractFactory( diff --git a/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts b/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts new file mode 100644 index 00000000000..368d60a46f0 --- /dev/null +++ b/contracts/test/v0.8/operatorforwarder/AuthorizedForwarder.test.ts @@ -0,0 +1,724 @@ +import { ethers } from 'hardhat' +import { publicAbi } from '../../test-helpers/helpers' +import { assert, expect } from 'chai' +import { Contract, ContractFactory, ContractReceipt } from 'ethers' +import { getUsers, Roles } from '../../test-helpers/setup' +import { evmRevert } from '../../test-helpers/matchers' + +let getterSetterFactory: ContractFactory +let forwarderFactory: ContractFactory +let brokenFactory: ContractFactory +let linkTokenFactory: ContractFactory + +let roles: Roles +const zeroAddress = ethers.constants.AddressZero + +before(async () => { + const users = await getUsers() + + roles = users.roles + getterSetterFactory = await ethers.getContractFactory( + 'src/v0.4/tests/GetterSetter.sol:GetterSetter', + roles.defaultAccount, + ) + brokenFactory = await ethers.getContractFactory( + 'src/v0.8/tests/Broken.sol:Broken', + roles.defaultAccount, + ) + forwarderFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol:AuthorizedForwarder', + roles.defaultAccount, + ) + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + roles.defaultAccount, + ) +}) + +describe('AuthorizedForwarder', () => { + let link: Contract + let forwarder: Contract + + beforeEach(async () => { + link = await linkTokenFactory.connect(roles.defaultAccount).deploy() + forwarder = await forwarderFactory + .connect(roles.defaultAccount) + .deploy( + link.address, + await roles.defaultAccount.getAddress(), + zeroAddress, + '0x', + ) + }) + + it('has a limited public interface [ @skip-coverage ]', () => { + publicAbi(forwarder, [ + 'forward', + 'multiForward', + 'getAuthorizedSenders', + 'linkToken', + 'isAuthorizedSender', + 'ownerForward', + 'setAuthorizedSenders', + 'transferOwnershipWithMessage', + 'typeAndVersion', + // ConfirmedOwner + 'transferOwnership', + 'acceptOwnership', + 'owner', + ]) + }) + + describe('#typeAndVersion', () => { + it('describes the authorized forwarder', async () => { + assert.equal( + await forwarder.typeAndVersion(), + 'AuthorizedForwarder 1.1.0', + ) + }) + }) + + describe('deployment', () => { + it('sets the correct link token', async () => { + assert.equal(await forwarder.linkToken(), link.address) + }) + + it('reverts on zeroAddress value for link token', async () => { + await evmRevert( + forwarderFactory.connect(roles.defaultAccount).deploy( + zeroAddress, // Link Address + await roles.defaultAccount.getAddress(), + zeroAddress, + '0x', + ), + ) + }) + + it('sets no authorized senders', async () => { + const senders = await forwarder.getAuthorizedSenders() + assert.equal(senders.length, 0) + }) + }) + + describe('#setAuthorizedSenders', () => { + let newSenders: string[] + let receipt: ContractReceipt + describe('when called by the owner', () => { + describe('set authorized senders containing duplicate/s', () => { + beforeEach(async () => { + newSenders = [ + await roles.oracleNode1.getAddress(), + await roles.oracleNode1.getAddress(), + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + }) + it('reverts with a must not have duplicate senders message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders), + 'Must not have duplicate senders', + ) + }) + }) + + describe('setting 3 authorized senders', () => { + beforeEach(async () => { + newSenders = [ + await roles.oracleNode1.getAddress(), + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + const tx = await forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders) + receipt = await tx.wait() + }) + + it('adds the authorized nodes', async () => { + const authorizedSenders = await forwarder.getAuthorizedSenders() + assert.equal(newSenders.length, authorizedSenders.length) + for (let i = 0; i < authorizedSenders.length; i++) { + assert.equal(authorizedSenders[i], newSenders[i]) + } + }) + + it('emits an event', async () => { + assert.equal(receipt.events?.length, 1) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'AuthorizedSendersChanged') + const encodedSenders = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'address'], + [newSenders, await roles.defaultAccount.getAddress()], + ) + assert.equal(responseEvent?.data, encodedSenders) + }) + + it('replaces the authorized nodes', async () => { + const newSenders = await forwarder + .connect(roles.defaultAccount) + .getAuthorizedSenders() + assert.notIncludeOrderedMembers(newSenders, [ + await roles.oracleNode.getAddress(), + ]) + }) + + after(async () => { + await forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.oracleNode.getAddress()]) + }) + }) + + describe('setting 0 authorized senders', () => { + beforeEach(async () => { + newSenders = [] + }) + + it('reverts with a minimum senders message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders), + 'Must have at least 1 sender', + ) + }) + }) + }) + + describe('when called by a non-owner', () => { + it('cannot add an authorized node', async () => { + await evmRevert( + forwarder + .connect(roles.stranger) + .setAuthorizedSenders([await roles.stranger.getAddress()]), + 'Cannot set authorized senders', + ) + }) + }) + }) + + describe('#forward', () => { + let bytes: string + let payload: string + let mock: Contract + + beforeEach(async () => { + mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() + bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) + payload = getterSetterFactory.interface.encodeFunctionData( + getterSetterFactory.interface.getFunction('setBytes'), + [bytes], + ) + }) + + describe('when called by an unauthorized node', () => { + it('reverts', async () => { + await evmRevert( + forwarder.connect(roles.stranger).forward(mock.address, payload), + ) + }) + }) + + describe('when called by an authorized node', () => { + beforeEach(async () => { + await forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.defaultAccount.getAddress()]) + }) + + describe('when destination call reverts', () => { + let brokenMock: Contract + let brokenPayload: string + let brokenMsgPayload: string + + beforeEach(async () => { + brokenMock = await brokenFactory + .connect(roles.defaultAccount) + .deploy() + brokenMsgPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertWithMessage'), + ['Failure message'], + ) + + brokenPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertSilently'), + [], + ) + }) + + describe('when reverts with message', () => { + it('return revert message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .forward(brokenMock.address, brokenMsgPayload), + "reverted with reason string 'Failure message'", + ) + }) + }) + + describe('when reverts without message', () => { + it('return silent failure message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .forward(brokenMock.address, brokenPayload), + 'Forwarded call reverted without reason', + ) + }) + }) + }) + + describe('when sending to a non-contract address', () => { + it('reverts', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .forward(zeroAddress, payload), + 'Must forward to a contract', + ) + }) + }) + + describe('when attempting to forward to the link token', () => { + it('reverts', async () => { + const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .forward(link.address, sighash), + ) + }) + }) + + describe('when forwarding to any other address', () => { + it('forwards the data', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .forward(mock.address, payload) + await tx.wait() + assert.equal(await mock.getBytes(), bytes) + }) + + it('perceives the message is sent by the AuthorizedForwarder', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .forward(mock.address, payload) + await expect(tx) + .to.emit(mock, 'SetBytes') + .withArgs(forwarder.address, bytes) + }) + }) + }) + }) + + describe('#multiForward', () => { + let bytes: string + let payload: string + let mock: Contract + + beforeEach(async () => { + mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() + bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) + payload = getterSetterFactory.interface.encodeFunctionData( + getterSetterFactory.interface.getFunction('setBytes'), + [bytes], + ) + }) + + describe('when called by an unauthorized node', () => { + it('reverts', async () => { + await evmRevert( + forwarder + .connect(roles.stranger) + .multiForward([mock.address], [payload]), + ) + }) + }) + + describe('when it receives a single call by an authorized node', () => { + beforeEach(async () => { + await forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.defaultAccount.getAddress()]) + }) + + describe('when destination call reverts', () => { + let brokenMock: Contract + let brokenPayload: string + let brokenMsgPayload: string + + beforeEach(async () => { + brokenMock = await brokenFactory + .connect(roles.defaultAccount) + .deploy() + brokenMsgPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertWithMessage'), + ['Failure message'], + ) + + brokenPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertSilently'), + [], + ) + }) + + describe('when reverts with message', () => { + it('return revert message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([brokenMock.address], [brokenMsgPayload]), + "reverted with reason string 'Failure message'", + ) + }) + }) + + describe('when reverts without message', () => { + it('return silent failure message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([brokenMock.address], [brokenPayload]), + 'Forwarded call reverted without reason', + ) + }) + }) + }) + + describe('when sending to a non-contract address', () => { + it('reverts', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([zeroAddress], [payload]), + 'Must forward to a contract', + ) + }) + }) + + describe('when attempting to forward to the link token', () => { + it('reverts', async () => { + const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([link.address], [sighash]), + ) + }) + }) + + describe('when forwarding to any other address', () => { + it('forwards the data', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .multiForward([mock.address], [payload]) + await tx.wait() + assert.equal(await mock.getBytes(), bytes) + }) + + it('perceives the message is sent by the AuthorizedForwarder', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .multiForward([mock.address], [payload]) + await expect(tx) + .to.emit(mock, 'SetBytes') + .withArgs(forwarder.address, bytes) + }) + }) + }) + + describe('when its called by an authorized node', () => { + beforeEach(async () => { + await forwarder + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.defaultAccount.getAddress()]) + }) + + describe('when 1/1 calls reverts', () => { + let brokenMock: Contract + let brokenPayload: string + let brokenMsgPayload: string + + beforeEach(async () => { + brokenMock = await brokenFactory + .connect(roles.defaultAccount) + .deploy() + brokenMsgPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertWithMessage'), + ['Failure message'], + ) + + brokenPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertSilently'), + [], + ) + }) + + describe('when reverts with message', () => { + it('return revert message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([brokenMock.address], [brokenMsgPayload]), + "reverted with reason string 'Failure message'", + ) + }) + }) + + describe('when reverts without message', () => { + it('return silent failure message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([brokenMock.address], [brokenPayload]), + 'Forwarded call reverted without reason', + ) + }) + }) + }) + + describe('when 1/many calls revert', () => { + let brokenMock: Contract + let brokenPayload: string + let brokenMsgPayload: string + + beforeEach(async () => { + brokenMock = await brokenFactory + .connect(roles.defaultAccount) + .deploy() + brokenMsgPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertWithMessage'), + ['Failure message'], + ) + + brokenPayload = brokenFactory.interface.encodeFunctionData( + brokenFactory.interface.getFunction('revertSilently'), + [], + ) + }) + + describe('when reverts with message', () => { + it('return revert message', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward( + [brokenMock.address, mock.address], + [brokenMsgPayload, payload], + ), + "reverted with reason string 'Failure message'", + ) + + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward( + [mock.address, brokenMock.address], + [payload, brokenMsgPayload], + ), + "reverted with reason string 'Failure message'", + ) + }) + }) + + describe('when reverts without message', () => { + it('return silent failure message', async () => { + await evmRevert( + // first + forwarder + .connect(roles.defaultAccount) + .multiForward( + [brokenMock.address, mock.address], + [brokenPayload, payload], + ), + 'Forwarded call reverted without reason', + ) + + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward( + [mock.address, brokenMock.address], + [payload, brokenPayload], + ), + 'Forwarded call reverted without reason', + ) + }) + }) + }) + + describe('when sending to a non-contract address', () => { + it('reverts', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([zeroAddress], [payload]), + 'Must forward to a contract', + ) + }) + }) + + describe('when attempting to forward to the link token', () => { + it('reverts', async () => { + const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .multiForward([link.address], [sighash]), + ) + }) + }) + + describe('when forwarding to any other address', () => { + it('forwards the data', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .multiForward([mock.address], [payload]) + await tx.wait() + assert.equal(await mock.getBytes(), bytes) + }) + + it('perceives the message is sent by the AuthorizedForwarder', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .multiForward([mock.address], [payload]) + await expect(tx) + .to.emit(mock, 'SetBytes') + .withArgs(forwarder.address, bytes) + }) + }) + }) + }) + + describe('#transferOwnershipWithMessage', () => { + const message = '0x42' + + describe('when called by a non-owner', () => { + it('reverts', async () => { + await evmRevert( + forwarder + .connect(roles.stranger) + .transferOwnershipWithMessage( + await roles.stranger.getAddress(), + message, + ), + 'Only callable by owner', + ) + }) + }) + + describe('when called by the owner', () => { + it('calls the normal ownership transfer proposal', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .transferOwnershipWithMessage( + await roles.stranger.getAddress(), + message, + ) + const receipt = await tx.wait() + + assert.equal(receipt?.events?.[0]?.event, 'OwnershipTransferRequested') + assert.equal(receipt?.events?.[0]?.address, forwarder.address) + assert.equal( + receipt?.events?.[0]?.args?.[0], + await roles.defaultAccount.getAddress(), + ) + assert.equal( + receipt?.events?.[0]?.args?.[1], + await roles.stranger.getAddress(), + ) + }) + + it('calls the normal ownership transfer proposal', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .transferOwnershipWithMessage( + await roles.stranger.getAddress(), + message, + ) + const receipt = await tx.wait() + + assert.equal( + receipt?.events?.[1]?.event, + 'OwnershipTransferRequestedWithMessage', + ) + assert.equal(receipt?.events?.[1]?.address, forwarder.address) + assert.equal( + receipt?.events?.[1]?.args?.[0], + await roles.defaultAccount.getAddress(), + ) + assert.equal( + receipt?.events?.[1]?.args?.[1], + await roles.stranger.getAddress(), + ) + assert.equal(receipt?.events?.[1]?.args?.[2], message) + }) + }) + }) + + describe('#ownerForward', () => { + let bytes: string + let payload: string + let mock: Contract + + beforeEach(async () => { + mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() + bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) + payload = getterSetterFactory.interface.encodeFunctionData( + getterSetterFactory.interface.getFunction('setBytes'), + [bytes], + ) + }) + + describe('when called by a non-owner', () => { + it('reverts', async () => { + await evmRevert( + forwarder.connect(roles.stranger).ownerForward(mock.address, payload), + ) + }) + }) + + describe('when called by owner', () => { + describe('when attempting to forward to the link token', () => { + it('does not revert', async () => { + const sighash = linkTokenFactory.interface.getSighash('name') // any Link Token function + + await forwarder + .connect(roles.defaultAccount) + .ownerForward(link.address, sighash) + }) + }) + + describe('when forwarding to any other address', () => { + it('forwards the data', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .ownerForward(mock.address, payload) + await tx.wait() + assert.equal(await mock.getBytes(), bytes) + }) + + it('reverts when sending to a non-contract address', async () => { + await evmRevert( + forwarder + .connect(roles.defaultAccount) + .ownerForward(zeroAddress, payload), + 'Must forward to a contract', + ) + }) + + it('perceives the message is sent by the Operator', async () => { + const tx = await forwarder + .connect(roles.defaultAccount) + .ownerForward(mock.address, payload) + await expect(tx) + .to.emit(mock, 'SetBytes') + .withArgs(forwarder.address, bytes) + }) + }) + }) + }) +}) diff --git a/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts b/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts new file mode 100644 index 00000000000..3bd347320c5 --- /dev/null +++ b/contracts/test/v0.8/operatorforwarder/ConfirmedOwner.test.ts @@ -0,0 +1,136 @@ +import { ethers } from 'hardhat' +import { publicAbi } from '../../test-helpers/helpers' +import { assert, expect } from 'chai' +import { Contract, ContractFactory, Signer } from 'ethers' +import { Personas, getUsers } from '../../test-helpers/setup' +import { evmRevert } from '../../test-helpers/matchers' + +let confirmedOwnerTestHelperFactory: ContractFactory +let confirmedOwnerFactory: ContractFactory + +let personas: Personas +let owner: Signer +let nonOwner: Signer +let newOwner: Signer + +before(async () => { + const users = await getUsers() + personas = users.personas + owner = personas.Carol + nonOwner = personas.Neil + newOwner = personas.Ned + + confirmedOwnerTestHelperFactory = await ethers.getContractFactory( + 'src/v0.7/tests/ConfirmedOwnerTestHelper.sol:ConfirmedOwnerTestHelper', + owner, + ) + confirmedOwnerFactory = await ethers.getContractFactory( + 'src/v0.8/shared/access/ConfirmedOwner.sol:ConfirmedOwner', + owner, + ) +}) + +describe('ConfirmedOwner', () => { + let confirmedOwner: Contract + + beforeEach(async () => { + confirmedOwner = await confirmedOwnerTestHelperFactory + .connect(owner) + .deploy() + }) + + it('has a limited public interface [ @skip-coverage ]', () => { + publicAbi(confirmedOwner, [ + 'acceptOwnership', + 'owner', + 'transferOwnership', + // test helper public methods + 'modifierOnlyOwner', + ]) + }) + + describe('#constructor', () => { + it('assigns ownership to the deployer', async () => { + const [actual, expected] = await Promise.all([ + owner.getAddress(), + confirmedOwner.owner(), + ]) + + assert.equal(actual, expected) + }) + + it('reverts if assigned to the zero address', async () => { + await evmRevert( + confirmedOwnerFactory + .connect(owner) + .deploy(ethers.constants.AddressZero), + 'Cannot set owner to zero', + ) + }) + }) + + describe('#onlyOwner modifier', () => { + describe('when called by an owner', () => { + it('successfully calls the method', async () => { + const tx = await confirmedOwner.connect(owner).modifierOnlyOwner() + await expect(tx).to.emit(confirmedOwner, 'Here') + }) + }) + + describe('when called by anyone but the owner', () => { + it('reverts', async () => + await evmRevert(confirmedOwner.connect(nonOwner).modifierOnlyOwner())) + }) + }) + + describe('#transferOwnership', () => { + describe('when called by an owner', () => { + it('emits a log', async () => { + const tx = await confirmedOwner + .connect(owner) + .transferOwnership(await newOwner.getAddress()) + await expect(tx) + .to.emit(confirmedOwner, 'OwnershipTransferRequested') + .withArgs(await owner.getAddress(), await newOwner.getAddress()) + }) + + it('does not allow ownership transfer to self', async () => { + await evmRevert( + confirmedOwner + .connect(owner) + .transferOwnership(await owner.getAddress()), + 'Cannot transfer to self', + ) + }) + }) + }) + + describe('when called by anyone but the owner', () => { + it('reverts', async () => + await evmRevert( + confirmedOwner + .connect(nonOwner) + .transferOwnership(await newOwner.getAddress()), + )) + }) + + describe('#acceptOwnership', () => { + describe('after #transferOwnership has been called', () => { + beforeEach(async () => { + await confirmedOwner + .connect(owner) + .transferOwnership(await newOwner.getAddress()) + }) + + it('allows the recipient to call it', async () => { + const tx = await confirmedOwner.connect(newOwner).acceptOwnership() + await expect(tx) + .to.emit(confirmedOwner, 'OwnershipTransferred') + .withArgs(await owner.getAddress(), await newOwner.getAddress()) + }) + + it('does not allow a non-recipient to call it', async () => + await evmRevert(confirmedOwner.connect(nonOwner).acceptOwnership())) + }) + }) +}) diff --git a/contracts/test/v0.8/operatorforwarder/Operator.test.ts b/contracts/test/v0.8/operatorforwarder/Operator.test.ts new file mode 100644 index 00000000000..2c64c2dc93b --- /dev/null +++ b/contracts/test/v0.8/operatorforwarder/Operator.test.ts @@ -0,0 +1,3819 @@ +import { ethers } from 'hardhat' +import { + publicAbi, + toBytes32String, + toWei, + stringToBytes, + increaseTime5Minutes, + getLog, +} from '../../test-helpers/helpers' +import { assert, expect } from 'chai' +import { + BigNumber, + constants, + Contract, + ContractFactory, + ContractReceipt, + ContractTransaction, + Signer, +} from 'ethers' +import { getUsers, Roles } from '../../test-helpers/setup' +import { bigNumEquals, evmRevert } from '../../test-helpers/matchers' +import type { providers } from 'ethers' +import { + convertCancelParams, + convertCancelByRequesterParams, + convertFufillParams, + convertFulfill2Params, + decodeRunRequest, + encodeOracleRequest, + encodeRequestOracleData, + RunRequest, +} from '../../test-helpers/oracle' + +let v7ConsumerFactory: ContractFactory +let basicConsumerFactory: ContractFactory +let multiWordConsumerFactory: ContractFactory +let gasGuzzlingConsumerFactory: ContractFactory +let getterSetterFactory: ContractFactory +let maliciousRequesterFactory: ContractFactory +let maliciousConsumerFactory: ContractFactory +let maliciousMultiWordConsumerFactory: ContractFactory +let operatorFactory: ContractFactory +let forwarderFactory: ContractFactory +let linkTokenFactory: ContractFactory +const zeroAddress = ethers.constants.AddressZero + +let roles: Roles + +before(async () => { + const users = await getUsers() + + roles = users.roles + v7ConsumerFactory = await ethers.getContractFactory( + 'src/v0.7/tests/Consumer.sol:Consumer', + ) + basicConsumerFactory = await ethers.getContractFactory( + 'src/v0.6/tests/BasicConsumer.sol:BasicConsumer', + ) + multiWordConsumerFactory = await ethers.getContractFactory( + 'src/v0.7/tests/MultiWordConsumer.sol:MultiWordConsumer', + ) + gasGuzzlingConsumerFactory = await ethers.getContractFactory( + 'src/v0.6/tests/GasGuzzlingConsumer.sol:GasGuzzlingConsumer', + ) + getterSetterFactory = await ethers.getContractFactory( + 'src/v0.4/tests/GetterSetter.sol:GetterSetter', + ) + maliciousRequesterFactory = await ethers.getContractFactory( + 'src/v0.4/tests/MaliciousRequester.sol:MaliciousRequester', + ) + maliciousConsumerFactory = await ethers.getContractFactory( + 'src/v0.4/tests/MaliciousConsumer.sol:MaliciousConsumer', + ) + maliciousMultiWordConsumerFactory = await ethers.getContractFactory( + 'src/v0.6/tests/MaliciousMultiWordConsumer.sol:MaliciousMultiWordConsumer', + ) + operatorFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/Operator.sol:Operator', + ) + forwarderFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol:AuthorizedForwarder', + ) + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + ) +}) + +describe('Operator', () => { + let fHash: string + let specId: string + let to: string + let link: Contract + let operator: Contract + let forwarder1: Contract + let forwarder2: Contract + let owner: Signer + + beforeEach(async () => { + fHash = getterSetterFactory.interface.getSighash('requestedBytes32') + specId = + '0x4c7b7ffb66b344fbaa64995af81e355a00000000000000000000000000000000' + to = '0x80e29acb842498fe6591f020bd82766dce619d43' + link = await linkTokenFactory.connect(roles.defaultAccount).deploy() + owner = roles.defaultAccount + operator = await operatorFactory + .connect(owner) + .deploy(link.address, await owner.getAddress()) + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.oracleNode.getAddress()]) + }) + + it('has a limited public interface [ @skip-coverage ]', () => { + publicAbi(operator, [ + 'acceptAuthorizedReceivers', + 'acceptOwnableContracts', + 'cancelOracleRequest', + 'cancelOracleRequestByRequester', + 'distributeFunds', + 'fulfillOracleRequest', + 'fulfillOracleRequest2', + 'getAuthorizedSenders', + 'getChainlinkToken', + 'EXPIRYTIME', + 'isAuthorizedSender', + 'onTokenTransfer', + 'operatorRequest', + 'oracleRequest', + 'ownerForward', + 'ownerTransferAndCall', + 'setAuthorizedSenders', + 'setAuthorizedSendersOn', + 'transferOwnableContracts', + 'typeAndVersion', + 'withdraw', + 'withdrawable', + // Ownable methods: + 'acceptOwnership', + 'owner', + 'transferOwnership', + ]) + }) + + describe('#typeAndVersion', () => { + it('describes the operator', async () => { + assert.equal(await operator.typeAndVersion(), 'Operator 1.0.0') + }) + }) + + describe('#transferOwnableContracts', () => { + beforeEach(async () => { + forwarder1 = await forwarderFactory + .connect(owner) + .deploy(link.address, operator.address, zeroAddress, '0x') + forwarder2 = await forwarderFactory + .connect(owner) + .deploy(link.address, operator.address, zeroAddress, '0x') + }) + + describe('being called by the owner', () => { + it('cannot transfer to self', async () => { + await evmRevert( + operator + .connect(owner) + .transferOwnableContracts([forwarder1.address], operator.address), + 'Cannot transfer to self', + ) + }) + + it('emits an ownership transfer request event', async () => { + const tx = await operator + .connect(owner) + .transferOwnableContracts( + [forwarder1.address, forwarder2.address], + await roles.oracleNode1.getAddress(), + ) + const receipt = await tx.wait() + assert.equal(receipt?.events?.length, 2) + const log1 = receipt?.events?.[0] + assert.equal(log1?.event, 'OwnershipTransferRequested') + assert.equal(log1?.address, forwarder1.address) + assert.equal(log1?.args?.[0], operator.address) + assert.equal(log1?.args?.[1], await roles.oracleNode1.getAddress()) + const log2 = receipt?.events?.[1] + assert.equal(log2?.event, 'OwnershipTransferRequested') + assert.equal(log2?.address, forwarder2.address) + assert.equal(log2?.args?.[0], operator.address) + assert.equal(log2?.args?.[1], await roles.oracleNode1.getAddress()) + }) + }) + + describe('being called by a non-owner', () => { + it('reverts with message', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .transferOwnableContracts( + [forwarder1.address], + await roles.oracleNode2.getAddress(), + ), + 'Only callable by owner', + ) + }) + }) + }) + + describe('#acceptOwnableContracts', () => { + describe('being called by the owner', () => { + let operator2: Contract + let receipt: ContractReceipt + + beforeEach(async () => { + operator2 = await operatorFactory + .connect(roles.defaultAccount) + .deploy(link.address, await roles.defaultAccount.getAddress()) + forwarder1 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, zeroAddress, '0x') + forwarder2 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, zeroAddress, '0x') + await operator + .connect(roles.defaultAccount) + .transferOwnableContracts( + [forwarder1.address, forwarder2.address], + operator2.address, + ) + const tx = await operator2 + .connect(roles.defaultAccount) + .acceptOwnableContracts([forwarder1.address, forwarder2.address]) + receipt = await tx.wait() + }) + + it('sets the new owner on the forwarder', async () => { + assert.equal(await forwarder1.owner(), operator2.address) + }) + + it('emits ownership transferred events', async () => { + assert.equal(receipt?.events?.[0]?.event, 'OwnableContractAccepted') + assert.equal(receipt?.events?.[0]?.args?.[0], forwarder1.address) + + assert.equal(receipt?.events?.[1]?.event, 'OwnershipTransferred') + assert.equal(receipt?.events?.[1]?.address, forwarder1.address) + assert.equal(receipt?.events?.[1]?.args?.[0], operator.address) + assert.equal(receipt?.events?.[1]?.args?.[1], operator2.address) + + assert.equal(receipt?.events?.[2]?.event, 'OwnableContractAccepted') + assert.equal(receipt?.events?.[2]?.args?.[0], forwarder2.address) + + assert.equal(receipt?.events?.[3]?.event, 'OwnershipTransferred') + assert.equal(receipt?.events?.[3]?.address, forwarder2.address) + assert.equal(receipt?.events?.[3]?.args?.[0], operator.address) + assert.equal(receipt?.events?.[3]?.args?.[1], operator2.address) + }) + }) + + describe('being called by a non-owner authorized sender', () => { + it('does not revert', async () => { + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.oracleNode1.getAddress()]) + + await operator.connect(roles.oracleNode1).acceptOwnableContracts([]) + }) + }) + + describe('being called by a non owner', () => { + it('reverts with message', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .acceptOwnableContracts([await roles.oracleNode2.getAddress()]), + 'Cannot set authorized senders', + ) + }) + }) + }) + + describe('#distributeFunds', () => { + describe('when called with empty arrays', () => { + it('reverts with invalid array message', async () => { + await evmRevert( + operator.connect(roles.defaultAccount).distributeFunds([], []), + 'Invalid array length(s)', + ) + }) + }) + + describe('when called with unequal array lengths', () => { + it('reverts with invalid array message', async () => { + const receivers = [ + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + const amounts = [1, 2, 3] + await evmRevert( + operator + .connect(roles.defaultAccount) + .distributeFunds(receivers, amounts), + 'Invalid array length(s)', + ) + }) + }) + + describe('when called with not enough ETH', () => { + it('reverts with subtraction overflow message', async () => { + const amountToSend = toWei('2') + const ethSent = toWei('1') + await evmRevert( + operator + .connect(roles.defaultAccount) + .distributeFunds( + [await roles.oracleNode2.getAddress()], + [amountToSend], + { + value: ethSent, + }, + ), + 'Arithmetic operation underflowed or overflowed outside of an unchecked block', + ) + }) + }) + + describe('when called with too much ETH', () => { + it('reverts with too much ETH message', async () => { + const amountToSend = toWei('2') + const ethSent = toWei('3') + await evmRevert( + operator + .connect(roles.defaultAccount) + .distributeFunds( + [await roles.oracleNode2.getAddress()], + [amountToSend], + { + value: ethSent, + }, + ), + 'Too much ETH sent', + ) + }) + }) + + describe('when called with correct values', () => { + it('updates the balances', async () => { + const node2BalanceBefore = await roles.oracleNode2.getBalance() + const node3BalanceBefore = await roles.oracleNode3.getBalance() + const receivers = [ + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + const sendNode2 = toWei('2') + const sendNode3 = toWei('3') + const totalAmount = toWei('5') + const amounts = [sendNode2, sendNode3] + + await operator + .connect(roles.defaultAccount) + .distributeFunds(receivers, amounts, { value: totalAmount }) + + const node2BalanceAfter = await roles.oracleNode2.getBalance() + const node3BalanceAfter = await roles.oracleNode3.getBalance() + + assert.equal( + node2BalanceAfter.sub(node2BalanceBefore).toString(), + sendNode2.toString(), + ) + + assert.equal( + node3BalanceAfter.sub(node3BalanceBefore).toString(), + sendNode3.toString(), + ) + }) + }) + }) + + describe('#setAuthorizedSenders', () => { + let newSenders: string[] + let receipt: ContractReceipt + describe('when called by the owner', () => { + describe('setting 3 authorized senders', () => { + beforeEach(async () => { + newSenders = [ + await roles.oracleNode1.getAddress(), + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + const tx = await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders) + receipt = await tx.wait() + }) + + it('adds the authorized nodes', async () => { + const authorizedSenders = await operator.getAuthorizedSenders() + assert.equal(newSenders.length, authorizedSenders.length) + for (let i = 0; i < authorizedSenders.length; i++) { + assert.equal(authorizedSenders[i], newSenders[i]) + } + }) + + it('emits an event on the Operator', async () => { + assert.equal(receipt.events?.length, 1) + + const encodedSenders1 = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'address'], + [newSenders, await roles.defaultAccount.getAddress()], + ) + + const responseEvent1 = receipt.events?.[0] + assert.equal(responseEvent1?.event, 'AuthorizedSendersChanged') + assert.equal(responseEvent1?.data, encodedSenders1) + }) + + it('replaces the authorized nodes', async () => { + const originalAuthorization = await operator + .connect(roles.defaultAccount) + .isAuthorizedSender(await roles.oracleNode.getAddress()) + assert.isFalse(originalAuthorization) + }) + + after(async () => { + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.oracleNode.getAddress()]) + }) + }) + + describe('setting 0 authorized senders', () => { + beforeEach(async () => { + newSenders = [] + }) + + it('reverts with a minimum senders message', async () => { + await evmRevert( + operator + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders), + 'Must have at least 1 sender', + ) + }) + }) + }) + + describe('when called by an authorized sender', () => { + beforeEach(async () => { + newSenders = [await roles.oracleNode1.getAddress()] + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders(newSenders) + }) + + it('succeeds', async () => { + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.stranger.getAddress()]) + }) + }) + + describe('when called by a non-owner', () => { + it('cannot add an authorized node', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .setAuthorizedSenders([await roles.stranger.getAddress()]), + 'Cannot set authorized senders', + ) + }) + }) + }) + + describe('#setAuthorizedSendersOn', () => { + let newSenders: string[] + + beforeEach(async () => { + await operator + .connect(roles.defaultAccount) + .setAuthorizedSenders([await roles.oracleNode1.getAddress()]) + newSenders = [ + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + + forwarder1 = await forwarderFactory + .connect(owner) + .deploy(link.address, operator.address, zeroAddress, '0x') + forwarder2 = await forwarderFactory + .connect(owner) + .deploy(link.address, operator.address, zeroAddress, '0x') + }) + + describe('when called by a non-authorized sender', () => { + it('reverts', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .setAuthorizedSendersOn(newSenders, [forwarder1.address]), + 'Cannot set authorized senders', + ) + }) + }) + + describe('when called by an owner', () => { + it('does not revert', async () => { + await operator + .connect(roles.defaultAccount) + .setAuthorizedSendersOn( + [forwarder1.address, forwarder2.address], + newSenders, + ) + }) + }) + + describe('when called by an authorized sender', () => { + it('does not revert', async () => { + await operator + .connect(roles.oracleNode1) + .setAuthorizedSendersOn( + [forwarder1.address, forwarder2.address], + newSenders, + ) + }) + + it('does revert with 0 senders', async () => { + await operator + .connect(roles.oracleNode1) + .setAuthorizedSendersOn( + [forwarder1.address, forwarder2.address], + newSenders, + ) + }) + + it('emits a log announcing the change and who made it', async () => { + const targets = [forwarder1.address, forwarder2.address] + const tx = await operator + .connect(roles.oracleNode1) + .setAuthorizedSendersOn(targets, newSenders) + + const receipt = await tx.wait() + const encodedArgs = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'address[]', 'address'], + [targets, newSenders, await roles.oracleNode1.getAddress()], + ) + + const event1 = receipt.events?.[0] + assert.equal(event1?.event, 'TargetsUpdatedAuthorizedSenders') + assert.equal(event1?.address, operator.address) + assert.equal(event1?.data, encodedArgs) + }) + + it('updates the sender list on each of the targets', async () => { + const tx = await operator + .connect(roles.oracleNode1) + .setAuthorizedSendersOn( + [forwarder1.address, forwarder2.address], + newSenders, + ) + + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 3, receipt.toString()) + const encodedSenders = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'address'], + [newSenders, operator.address], + ) + + const event1 = receipt.events?.[1] + assert.equal(event1?.event, 'AuthorizedSendersChanged') + assert.equal(event1?.address, forwarder1.address) + assert.equal(event1?.data, encodedSenders) + + const event2 = receipt.events?.[2] + assert.equal(event2?.event, 'AuthorizedSendersChanged') + assert.equal(event2?.address, forwarder2.address) + assert.equal(event2?.data, encodedSenders) + }) + }) + }) + + describe('#acceptAuthorizedReceivers', () => { + let newSenders: string[] + + describe('being called by the owner', () => { + let operator2: Contract + let receipt: ContractReceipt + + beforeEach(async () => { + operator2 = await operatorFactory + .connect(roles.defaultAccount) + .deploy(link.address, await roles.defaultAccount.getAddress()) + forwarder1 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, zeroAddress, '0x') + forwarder2 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, zeroAddress, '0x') + await operator + .connect(roles.defaultAccount) + .transferOwnableContracts( + [forwarder1.address, forwarder2.address], + operator2.address, + ) + newSenders = [ + await roles.oracleNode2.getAddress(), + await roles.oracleNode3.getAddress(), + ] + + const tx = await operator2 + .connect(roles.defaultAccount) + .acceptAuthorizedReceivers( + [forwarder1.address, forwarder2.address], + newSenders, + ) + receipt = await tx.wait() + }) + + it('sets the new owner on the forwarder', async () => { + assert.equal(await forwarder1.owner(), operator2.address) + }) + + it('emits ownership transferred events', async () => { + assert.equal(receipt?.events?.[0]?.event, 'OwnableContractAccepted') + assert.equal(receipt?.events?.[0]?.args?.[0], forwarder1.address) + + assert.equal(receipt?.events?.[1]?.event, 'OwnershipTransferred') + assert.equal(receipt?.events?.[1]?.address, forwarder1.address) + assert.equal(receipt?.events?.[1]?.args?.[0], operator.address) + assert.equal(receipt?.events?.[1]?.args?.[1], operator2.address) + + assert.equal(receipt?.events?.[2]?.event, 'OwnableContractAccepted') + assert.equal(receipt?.events?.[2]?.args?.[0], forwarder2.address) + + assert.equal(receipt?.events?.[3]?.event, 'OwnershipTransferred') + assert.equal(receipt?.events?.[3]?.address, forwarder2.address) + assert.equal(receipt?.events?.[3]?.args?.[0], operator.address) + assert.equal(receipt?.events?.[3]?.args?.[1], operator2.address) + + assert.equal( + receipt?.events?.[4]?.event, + 'TargetsUpdatedAuthorizedSenders', + ) + + const encodedSenders = ethers.utils.defaultAbiCoder.encode( + ['address[]', 'address'], + [newSenders, operator2.address], + ) + assert.equal(receipt?.events?.[5]?.event, 'AuthorizedSendersChanged') + assert.equal(receipt?.events?.[5]?.address, forwarder1.address) + assert.equal(receipt?.events?.[5]?.data, encodedSenders) + + assert.equal(receipt?.events?.[6]?.event, 'AuthorizedSendersChanged') + assert.equal(receipt?.events?.[6]?.address, forwarder2.address) + assert.equal(receipt?.events?.[6]?.data, encodedSenders) + }) + }) + + describe('being called by a non owner', () => { + it('reverts with message', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .acceptAuthorizedReceivers( + [forwarder1.address, forwarder2.address], + newSenders, + ), + 'Cannot set authorized senders', + ) + }) + }) + }) + + describe('#onTokenTransfer', () => { + describe('when called from any address but the LINK token', () => { + it('triggers the intended method', async () => { + const callData = encodeOracleRequest( + specId, + to, + fHash, + 0, + constants.HashZero, + ) + + await evmRevert( + operator.onTokenTransfer( + await roles.defaultAccount.getAddress(), + 0, + callData, + ), + ) + }) + }) + + describe('when called from the LINK token', () => { + it('triggers the intended method', async () => { + const callData = encodeOracleRequest( + specId, + to, + fHash, + 0, + constants.HashZero, + ) + + const tx = await link.transferAndCall(operator.address, 0, callData, { + value: 0, + }) + const receipt = await tx.wait() + + assert.equal(3, receipt.logs?.length) + }) + + describe('with no data', () => { + it('reverts', async () => { + await evmRevert( + link.transferAndCall(operator.address, 0, '0x', { + value: 0, + }), + ) + }) + }) + }) + + describe('malicious requester', () => { + let mock: Contract + let requester: Contract + const paymentAmount = toWei('1') + + beforeEach(async () => { + mock = await maliciousRequesterFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(mock.address, paymentAmount) + }) + + it('cannot withdraw from oracle', async () => { + const operatorOriginalBalance = await link.balanceOf(operator.address) + const mockOriginalBalance = await link.balanceOf(mock.address) + + await evmRevert(mock.maliciousWithdraw()) + + const operatorNewBalance = await link.balanceOf(operator.address) + const mockNewBalance = await link.balanceOf(mock.address) + + bigNumEquals(operatorOriginalBalance, operatorNewBalance) + bigNumEquals(mockNewBalance, mockOriginalBalance) + }) + + describe('if the requester tries to create a requestId for another contract', () => { + it('the requesters ID will not match with the oracle contract', async () => { + const tx = await mock.maliciousTargetConsumer(to) + const receipt = await tx.wait() + + const mockRequestId = receipt.logs?.[0].data + const requestId = (receipt.events?.[0].args as any).requestId + assert.notEqual(mockRequestId, requestId) + }) + + it('the target requester can still create valid requests', async () => { + requester = await basicConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + await link.transfer(requester.address, paymentAmount) + await mock.maliciousTargetConsumer(requester.address) + await requester.requestEthereumPrice('USD', paymentAmount) + }) + }) + }) + + it('does not allow recursive calls of onTokenTransfer', async () => { + const requestPayload = encodeOracleRequest( + specId, + to, + fHash, + 0, + constants.HashZero, + ) + + const ottSelector = + operatorFactory.interface.getSighash('onTokenTransfer') + const header = + '000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef' + // to + '0000000000000000000000000000000000000000000000000000000000000539' + // amount + '0000000000000000000000000000000000000000000000000000000000000060' + // offset + '0000000000000000000000000000000000000000000000000000000000000136' // length + + const maliciousPayload = ottSelector + header + requestPayload.slice(2) + + await evmRevert( + link.transferAndCall(operator.address, 0, maliciousPayload, { + value: 0, + }), + ) + }) + }) + + describe('#oracleRequest', () => { + describe('when called through the LINK token', () => { + const paid = 100 + let log: providers.Log | undefined + let receipt: providers.TransactionReceipt + + beforeEach(async () => { + const args = encodeOracleRequest( + specId, + to, + fHash, + 1, + constants.HashZero, + ) + const tx = await link.transferAndCall(operator.address, paid, args) + receipt = await tx.wait() + assert.equal(3, receipt?.logs?.length) + + log = receipt.logs && receipt.logs[2] + }) + + it('logs an event', async () => { + assert.equal(operator.address, log?.address) + + assert.equal(log?.topics?.[1], specId) + + const req = decodeRunRequest(receipt?.logs?.[2]) + assert.equal(await roles.defaultAccount.getAddress(), req.requester) + bigNumEquals(paid, req.payment) + }) + + it('uses the expected event signature', async () => { + // If updating this test, be sure to update models.RunLogTopic. + const eventSignature = + '0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65' + assert.equal(eventSignature, log?.topics?.[0]) + }) + + it('does not allow the same requestId to be used twice', async () => { + const args2 = encodeOracleRequest( + specId, + to, + fHash, + 1, + constants.HashZero, + ) + await evmRevert(link.transferAndCall(operator.address, paid, args2)) + }) + + describe('when called with a payload less than 2 EVM words + function selector', () => { + it('throws an error', async () => { + const funcSelector = + operatorFactory.interface.getSighash('oracleRequest') + const maliciousData = + funcSelector + + '0000000000000000000000000000000000000000000000000000000000000000000' + await evmRevert( + link.transferAndCall(operator.address, paid, maliciousData), + ) + }) + }) + + describe('when called with a payload between 3 and 9 EVM words', () => { + it('throws an error', async () => { + const funcSelector = + operatorFactory.interface.getSighash('oracleRequest') + const maliciousData = + funcSelector + + '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' + await evmRevert( + link.transferAndCall(operator.address, paid, maliciousData), + ) + }) + }) + }) + + describe('when dataVersion is higher than 255', () => { + it('throws an error', async () => { + const paid = 100 + const args = encodeOracleRequest( + specId, + to, + fHash, + 1, + constants.HashZero, + 256, + ) + await evmRevert(link.transferAndCall(operator.address, paid, args)) + }) + }) + + describe('when not called through the LINK token', () => { + it('reverts', async () => { + await evmRevert( + operator + .connect(roles.oracleNode) + .oracleRequest( + '0x0000000000000000000000000000000000000000', + 0, + specId, + to, + fHash, + 1, + 1, + '0x', + ), + ) + }) + }) + }) + + describe('#operatorRequest', () => { + describe('when called through the LINK token', () => { + const paid = 100 + let log: providers.Log | undefined + let receipt: providers.TransactionReceipt + + beforeEach(async () => { + const args = encodeRequestOracleData( + specId, + fHash, + 1, + constants.HashZero, + ) + const tx = await link.transferAndCall(operator.address, paid, args) + receipt = await tx.wait() + assert.equal(3, receipt?.logs?.length) + + log = receipt.logs && receipt.logs[2] + }) + + it('logs an event', async () => { + assert.equal(operator.address, log?.address) + + assert.equal(log?.topics?.[1], specId) + + const req = decodeRunRequest(receipt?.logs?.[2]) + assert.equal(await roles.defaultAccount.getAddress(), req.requester) + bigNumEquals(paid, req.payment) + }) + + it('uses the expected event signature', async () => { + // If updating this test, be sure to update models.RunLogTopic. + const eventSignature = + '0xd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65' + assert.equal(eventSignature, log?.topics?.[0]) + }) + + it('does not allow the same requestId to be used twice', async () => { + const args2 = encodeRequestOracleData( + specId, + fHash, + 1, + constants.HashZero, + ) + await evmRevert(link.transferAndCall(operator.address, paid, args2)) + }) + + describe('when called with a payload less than 2 EVM words + function selector', () => { + it('throws an error', async () => { + const funcSelector = + operatorFactory.interface.getSighash('oracleRequest') + const maliciousData = + funcSelector + + '0000000000000000000000000000000000000000000000000000000000000000000' + await evmRevert( + link.transferAndCall(operator.address, paid, maliciousData), + ) + }) + }) + + describe('when called with a payload between 3 and 9 EVM words', () => { + it('throws an error', async () => { + const funcSelector = + operatorFactory.interface.getSighash('oracleRequest') + const maliciousData = + funcSelector + + '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' + await evmRevert( + link.transferAndCall(operator.address, paid, maliciousData), + ) + }) + }) + }) + + describe('when dataVersion is higher than 255', () => { + it('throws an error', async () => { + const paid = 100 + const args = encodeRequestOracleData( + specId, + fHash, + 1, + constants.HashZero, + 256, + ) + await evmRevert(link.transferAndCall(operator.address, paid, args)) + }) + }) + + describe('when not called through the LINK token', () => { + it('reverts', async () => { + await evmRevert( + operator + .connect(roles.oracleNode) + .oracleRequest( + '0x0000000000000000000000000000000000000000', + 0, + specId, + to, + fHash, + 1, + 1, + '0x', + ), + ) + }) + }) + }) + + describe('#fulfillOracleRequest', () => { + const response = 'Hi Mom!' + let maliciousRequester: Contract + let basicConsumer: Contract + let maliciousConsumer: Contract + let gasGuzzlingConsumer: Contract + let request: ReturnType + + describe('gas guzzling consumer [ @skip-coverage ]', () => { + beforeEach(async () => { + gasGuzzlingConsumer = await gasGuzzlingConsumerFactory + .connect(roles.consumer) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(gasGuzzlingConsumer.address, paymentAmount) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('emits an OracleResponse event', async () => { + const fulfillParams = convertFufillParams(request, response) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 1) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + }) + + describe('cooperative consumer', () => { + beforeEach(async () => { + basicConsumer = await basicConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(basicConsumer.address, paymentAmount) + const currency = 'USD' + const tx = await basicConsumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + describe('when called by an unauthorized node', () => { + beforeEach(async () => { + assert.equal( + false, + await operator.isAuthorizedSender( + await roles.stranger.getAddress(), + ), + ) + }) + + it('raises an error', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .fulfillOracleRequest(...convertFufillParams(request, response)), + ) + }) + }) + + describe('when fulfilled with the wrong function', () => { + let v7Consumer + beforeEach(async () => { + v7Consumer = await v7ConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(v7Consumer.address, paymentAmount) + const currency = 'USD' + const tx = await v7Consumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('raises an error', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .fulfillOracleRequest(...convertFufillParams(request, response)), + ) + }) + }) + + describe('when called by an authorized node', () => { + it('raises an error if the request ID does not exist', async () => { + request.requestId = ethers.utils.formatBytes32String('DOESNOTEXIST') + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)), + ) + }) + + it('sets the value on the requested contract', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + const currentValue = await basicConsumer.currentPrice() + assert.equal(response, ethers.utils.parseBytes32String(currentValue)) + }) + + it('emits an OracleResponse event', async () => { + const fulfillParams = convertFufillParams(request, response) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 3) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + + it('does not allow a request to be fulfilled twice', async () => { + const response2 = response + ' && Hello World!!' + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response2)), + ) + + const currentValue = await basicConsumer.currentPrice() + assert.equal(response, ethers.utils.parseBytes32String(currentValue)) + }) + }) + + describe('when the oracle does not provide enough gas', () => { + // if updating this defaultGasLimit, be sure it matches with the + // defaultGasLimit specified in store/tx_manager.go + const defaultGasLimit = 500000 + + beforeEach(async () => { + bigNumEquals(0, await operator.withdrawable()) + }) + + it('does not allow the oracle to withdraw the payment', async () => { + await evmRevert( + operator.connect(roles.oracleNode).fulfillOracleRequest( + ...convertFufillParams(request, response, { + gasLimit: 70000, + }), + ), + ) + + bigNumEquals(0, await operator.withdrawable()) + }) + + it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { + await operator.connect(roles.oracleNode).fulfillOracleRequest( + ...convertFufillParams(request, response, { + gasLimit: defaultGasLimit, + }), + ) + + bigNumEquals(request.payment, await operator.withdrawable()) + }) + }) + }) + + describe('with a malicious requester', () => { + beforeEach(async () => { + const paymentAmount = toWei('1') + maliciousRequester = await maliciousRequesterFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousRequester.address, paymentAmount) + }) + + it('cannot cancel before the expiration', async () => { + await evmRevert( + maliciousRequester.maliciousRequestCancel( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ), + ) + }) + + it('cannot call functions on the LINK token through callbacks', async () => { + await evmRevert( + maliciousRequester.request( + specId, + link.address, + ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + ), + ) + }) + + describe('requester lies about amount of LINK sent', () => { + it('the oracle uses the amount of LINK actually paid', async () => { + const tx = await maliciousRequester.maliciousPrice(specId) + const receipt = await tx.wait() + const req = decodeRunRequest(receipt.logs?.[3]) + + assert(toWei('1').eq(req.payment)) + }) + }) + }) + + describe('with a malicious consumer', () => { + const paymentAmount = toWei('1') + + beforeEach(async () => { + maliciousConsumer = await maliciousConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousConsumer.address, paymentAmount) + }) + + describe('fails during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response2)), + ) + }) + }) + + describe('calls selfdestruct', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + await maliciousConsumer.remove() + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + }) + + describe('request is canceled during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('cancelRequestOnFulfill(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + const mockBalance = await link.balanceOf(maliciousConsumer.address) + bigNumEquals(mockBalance, 0) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response2)), + ) + }) + }) + + describe('tries to steal funds from node', () => { + it('is not successful with call', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with send', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with transfer', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, response)) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + }) + + describe('when calling an owned contract', () => { + beforeEach(async () => { + forwarder1 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, link.address, operator.address, '0x') + }) + + it('does not allow the contract to callback to owned contracts', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('whatever(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + let request = decodeRunRequest(receipt.logs?.[3]) + let responseParams = convertFufillParams(request, response) + // set the params to be the owned address + responseParams[2] = forwarder1.address + + //accept ownership + await operator + .connect(roles.defaultAccount) + .acceptOwnableContracts([forwarder1.address]) + + // do the thing + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...responseParams), + 'Cannot call owned contract', + ) + + await operator + .connect(roles.defaultAccount) + .transferOwnableContracts([forwarder1.address], link.address) + //reverts for a different reason after transferring ownership + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...responseParams), + 'Params do not match request ID', + ) + }) + }) + }) + }) + + describe('#fulfillOracleRequest2', () => { + describe('single word fulfils', () => { + const response = 'Hi mom!' + const responseTypes = ['bytes32'] + const responseValues = [toBytes32String(response)] + let maliciousRequester: Contract + let basicConsumer: Contract + let maliciousConsumer: Contract + let gasGuzzlingConsumer: Contract + let request: ReturnType + let request2: ReturnType + + describe('gas guzzling consumer [ @skip-coverage ]', () => { + beforeEach(async () => { + gasGuzzlingConsumer = await gasGuzzlingConsumerFactory + .connect(roles.consumer) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(gasGuzzlingConsumer.address, paymentAmount) + const tx = + await gasGuzzlingConsumer.gassyRequestEthereumPrice(paymentAmount) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 1) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + }) + + describe('cooperative consumer', () => { + beforeEach(async () => { + basicConsumer = await basicConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(basicConsumer.address, paymentAmount) + const currency = 'USD' + const tx = await basicConsumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + describe('when called by an unauthorized node', () => { + beforeEach(async () => { + assert.equal( + false, + await operator.isAuthorizedSender( + await roles.stranger.getAddress(), + ), + ) + }) + + it('raises an error', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + }) + + describe('when called by an authorized node', () => { + it('raises an error if the request ID does not exist', async () => { + request.requestId = ethers.utils.formatBytes32String('DOESNOTEXIST') + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + + it('sets the value on the requested contract', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const currentValue = await basicConsumer.currentPrice() + assert.equal( + response, + ethers.utils.parseBytes32String(currentValue), + ) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 3) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + + it('does not allow a request to be fulfilled twice', async () => { + const response2 = response + ' && Hello World!!' + const response2Values = [toBytes32String(response2)] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + + const currentValue = await basicConsumer.currentPrice() + assert.equal( + response, + ethers.utils.parseBytes32String(currentValue), + ) + }) + }) + + describe('when the oracle does not provide enough gas', () => { + // if updating this defaultGasLimit, be sure it matches with the + // defaultGasLimit specified in store/tx_manager.go + const defaultGasLimit = 500000 + + beforeEach(async () => { + bigNumEquals(0, await operator.withdrawable()) + }) + + it('does not allow the oracle to withdraw the payment', async () => { + await evmRevert( + operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + { + gasLimit: 70000, + }, + ), + ), + ) + + bigNumEquals(0, await operator.withdrawable()) + }) + + it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { + await operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params(request, responseTypes, responseValues, { + gasLimit: defaultGasLimit, + }), + ) + + bigNumEquals(request.payment, await operator.withdrawable()) + }) + }) + }) + + describe('with a malicious oracle', () => { + beforeEach(async () => { + // Setup Request 1 + basicConsumer = await basicConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(basicConsumer.address, paymentAmount) + const currency = 'USD' + const tx = await basicConsumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + // Setup Request 2 + await link.transfer(basicConsumer.address, paymentAmount) + const tx2 = await basicConsumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt2 = await tx2.wait() + request2 = decodeRunRequest(receipt2.logs?.[3]) + }) + + it('cannot spoof requestId in response data by moving calldata offset', async () => { + // Malicious Oracle Fulfill 2 + const functionSelector = '0x6ae0bc76' // fulfillOracleRequest2 + const dataOffset = + '0000000000000000000000000000000000000000000000000000000000000100' // Moved to 0x0124 + const fillerBytes = + '0000000000000000000000000000000000000000000000000000000000000000' + const expectedCalldataStart = request.requestId.slice(2) // 0xe4, this is checked against requestId in validateMultiWordResponseId + const dataSize = + '0000000000000000000000000000000000000000000000000000000000000040' // Two 32 byte blocks + const maliciousCalldataId = request2.requestId.slice(2) // 0x0124, set to a different requestId + const calldataData = + '1122334455667788991122334455667788991122334455667788991122334455' // some garbage value as response value + + const data = + functionSelector + + /** Input Params - slice off 0x prefix and pad with 0's */ + request.requestId.slice(2) + + request.payment.slice(2).padStart(64, '0') + + request.callbackAddr.slice(2).padStart(64, '0') + + request.callbackFunc.slice(2).padEnd(64, '0') + + request.expiration.slice(2).padStart(64, '0') + + // calldata "data" + dataOffset + + fillerBytes + + expectedCalldataStart + + dataSize + + maliciousCalldataId + + calldataData + + await evmRevert( + operator.connect(roles.oracleNode).signer.sendTransaction({ + to: operator.address, + data, + }), + ) + }) + }) + + describe('with a malicious requester', () => { + beforeEach(async () => { + const paymentAmount = toWei('1') + maliciousRequester = await maliciousRequesterFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousRequester.address, paymentAmount) + }) + + it('cannot cancel before the expiration', async () => { + await evmRevert( + maliciousRequester.maliciousRequestCancel( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ), + ) + }) + + it('cannot call functions on the LINK token through callbacks', async () => { + await evmRevert( + maliciousRequester.request( + specId, + link.address, + ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + ), + ) + }) + + describe('requester lies about amount of LINK sent', () => { + it('the oracle uses the amount of LINK actually paid', async () => { + const tx = await maliciousRequester.maliciousPrice(specId) + const receipt = await tx.wait() + const req = decodeRunRequest(receipt.logs?.[3]) + + assert(toWei('1').eq(req.payment)) + }) + }) + }) + + describe('with a malicious consumer', () => { + const paymentAmount = toWei('1') + + beforeEach(async () => { + maliciousConsumer = await maliciousConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousConsumer.address, paymentAmount) + }) + + describe('fails during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + const response2Values = [toBytes32String(response2)] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + }) + }) + + describe('calls selfdestruct', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + await maliciousConsumer.remove() + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + }) + + describe('request is canceled during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes( + 'cancelRequestOnFulfill(bytes32,bytes32)', + ), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const mockBalance = await link.balanceOf(maliciousConsumer.address) + bigNumEquals(mockBalance, 0) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + const response2Values = [toBytes32String(response2)] + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + }) + }) + + describe('tries to steal funds from node', () => { + it('is not successful with call', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with send', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with transfer', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + }) + + describe('when calling an owned contract', () => { + beforeEach(async () => { + forwarder1 = await forwarderFactory + .connect(roles.defaultAccount) + .deploy(link.address, link.address, operator.address, '0x') + }) + + it('does not allow the contract to callback to owned contracts', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('whatever(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + let request = decodeRunRequest(receipt.logs?.[3]) + let responseParams = convertFufillParams(request, response) + // set the params to be the owned address + responseParams[2] = forwarder1.address + + //accept ownership + await operator + .connect(roles.defaultAccount) + .acceptOwnableContracts([forwarder1.address]) + + // do the thing + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...responseParams), + 'Cannot call owned contract', + ) + + await operator + .connect(roles.defaultAccount) + .transferOwnableContracts([forwarder1.address], link.address) + //reverts for a different reason after transferring ownership + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...responseParams), + 'Params do not match request ID', + ) + }) + }) + }) + }) + + describe('multi word fulfils', () => { + describe('one bytes parameter', () => { + const response = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.\ + Fusce euismod malesuada ligula, eget semper metus ultrices sit amet.' + const responseTypes = ['bytes'] + const responseValues = [stringToBytes(response)] + let maliciousRequester: Contract + let multiConsumer: Contract + let maliciousConsumer: Contract + let gasGuzzlingConsumer: Contract + let request: ReturnType + + describe('gas guzzling consumer [ @skip-coverage ]', () => { + beforeEach(async () => { + gasGuzzlingConsumer = await gasGuzzlingConsumerFactory + .connect(roles.consumer) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(gasGuzzlingConsumer.address, paymentAmount) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 1) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + }) + + describe('cooperative consumer', () => { + beforeEach(async () => { + multiConsumer = await multiWordConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(multiConsumer.address, paymentAmount) + const currency = 'USD' + const tx = await multiConsumer.requestEthereumPrice( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it("matches the consumer's request ID", async () => { + const nonce = await multiConsumer.publicGetNextRequestCount() + const tx = await multiConsumer.requestEthereumPrice('USD', 0) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + const packed = ethers.utils.solidityPack( + ['address', 'uint256'], + [multiConsumer.address, nonce], + ) + const expected = ethers.utils.keccak256(packed) + assert.equal(expected, request.requestId) + }) + + describe('when called by an unauthorized node', () => { + beforeEach(async () => { + assert.equal( + false, + await operator.isAuthorizedSender( + await roles.stranger.getAddress(), + ), + ) + }) + + it('raises an error', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + }) + + describe('when called by an authorized node', () => { + it('raises an error if the request ID does not exist', async () => { + request.requestId = + ethers.utils.formatBytes32String('DOESNOTEXIST') + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + + it('sets the value on the requested contract', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const currentValue = await multiConsumer.currentPrice() + assert.equal(response, ethers.utils.toUtf8String(currentValue)) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 3) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + + it('does not allow a request to be fulfilled twice', async () => { + const response2 = response + ' && Hello World!!' + const response2Values = [stringToBytes(response2)] + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + + const currentValue = await multiConsumer.currentPrice() + assert.equal(response, ethers.utils.toUtf8String(currentValue)) + }) + }) + + describe('when the oracle does not provide enough gas', () => { + // if updating this defaultGasLimit, be sure it matches with the + // defaultGasLimit specified in store/tx_manager.go + const defaultGasLimit = 500000 + + beforeEach(async () => { + bigNumEquals(0, await operator.withdrawable()) + }) + + it('does not allow the oracle to withdraw the payment', async () => { + await evmRevert( + operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + { + gasLimit: 70000, + }, + ), + ), + ) + + bigNumEquals(0, await operator.withdrawable()) + }) + + it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { + await operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + { + gasLimit: defaultGasLimit, + }, + ), + ) + + bigNumEquals(request.payment, await operator.withdrawable()) + }) + }) + }) + + describe('with a malicious requester', () => { + beforeEach(async () => { + const paymentAmount = toWei('1') + maliciousRequester = await maliciousRequesterFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousRequester.address, paymentAmount) + }) + + it('cannot cancel before the expiration', async () => { + await evmRevert( + maliciousRequester.maliciousRequestCancel( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ), + ) + }) + + it('cannot call functions on the LINK token through callbacks', async () => { + await evmRevert( + maliciousRequester.request( + specId, + link.address, + ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + ), + ) + }) + + describe('requester lies about amount of LINK sent', () => { + it('the oracle uses the amount of LINK actually paid', async () => { + const tx = await maliciousRequester.maliciousPrice(specId) + const receipt = await tx.wait() + const req = decodeRunRequest(receipt.logs?.[3]) + + assert(toWei('1').eq(req.payment)) + }) + }) + }) + + describe('with a malicious consumer', () => { + const paymentAmount = toWei('1') + + beforeEach(async () => { + maliciousConsumer = await maliciousMultiWordConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousConsumer.address, paymentAmount) + }) + + describe('fails during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + const response2Values = [stringToBytes(response2)] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + }) + }) + + describe('calls selfdestruct', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + await maliciousConsumer.remove() + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + }) + + describe('request is canceled during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes( + 'cancelRequestOnFulfill(bytes32,bytes32)', + ), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const mockBalance = await link.balanceOf( + maliciousConsumer.address, + ) + bigNumEquals(mockBalance, 0) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response2 = 'hack the planet 102' + const response2Values = [stringToBytes(response2)] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + response2Values, + ), + ), + ) + }) + }) + + describe('tries to steal funds from node', () => { + it('is not successful with call', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with send', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with transfer', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + }) + }) + }) + + describe('multiple bytes32 parameters', () => { + const response1 = '100' + const response2 = '7777777' + const response3 = 'forty two' + const responseTypes = ['bytes32', 'bytes32', 'bytes32'] + const responseValues = [ + toBytes32String(response1), + toBytes32String(response2), + toBytes32String(response3), + ] + let maliciousRequester: Contract + let multiConsumer: Contract + let maliciousConsumer: Contract + let gasGuzzlingConsumer: Contract + let request: ReturnType + + describe('gas guzzling consumer [ @skip-coverage ]', () => { + beforeEach(async () => { + gasGuzzlingConsumer = await gasGuzzlingConsumerFactory + .connect(roles.consumer) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(gasGuzzlingConsumer.address, paymentAmount) + const tx = + await gasGuzzlingConsumer.gassyMultiWordRequest(paymentAmount) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 1) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + }) + + describe('cooperative consumer', () => { + beforeEach(async () => { + multiConsumer = await multiWordConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(multiConsumer.address, paymentAmount) + const currency = 'USD' + const tx = await multiConsumer.requestMultipleParameters( + currency, + paymentAmount, + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + describe('when called by an unauthorized node', () => { + beforeEach(async () => { + assert.equal( + false, + await operator.isAuthorizedSender( + await roles.stranger.getAddress(), + ), + ) + }) + + it('raises an error', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + }) + + describe('when called by an authorized node', () => { + it('raises an error if the request ID does not exist', async () => { + request.requestId = + ethers.utils.formatBytes32String('DOESNOTEXIST') + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ), + ) + }) + + it('sets the value on the requested contract', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const firstValue = await multiConsumer.usd() + const secondValue = await multiConsumer.eur() + const thirdValue = await multiConsumer.jpy() + assert.equal( + response1, + ethers.utils.parseBytes32String(firstValue), + ) + assert.equal( + response2, + ethers.utils.parseBytes32String(secondValue), + ) + assert.equal( + response3, + ethers.utils.parseBytes32String(thirdValue), + ) + }) + + it('emits an OracleResponse2 event', async () => { + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + const tx = await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams) + const receipt = await tx.wait() + assert.equal(receipt.events?.length, 3) + const responseEvent = receipt.events?.[0] + assert.equal(responseEvent?.event, 'OracleResponse') + assert.equal(responseEvent?.args?.[0], request.requestId) + }) + + it('does not allow a request to be fulfilled twice', async () => { + const response4 = response3 + ' && Hello World!!' + const repeatedResponseValues = [ + toBytes32String(response1), + toBytes32String(response2), + toBytes32String(response4), + ] + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + repeatedResponseValues, + ), + ), + ) + + const firstValue = await multiConsumer.usd() + const secondValue = await multiConsumer.eur() + const thirdValue = await multiConsumer.jpy() + assert.equal( + response1, + ethers.utils.parseBytes32String(firstValue), + ) + assert.equal( + response2, + ethers.utils.parseBytes32String(secondValue), + ) + assert.equal( + response3, + ethers.utils.parseBytes32String(thirdValue), + ) + }) + }) + + describe('when the oracle does not provide enough gas', () => { + // if updating this defaultGasLimit, be sure it matches with the + // defaultGasLimit specified in store/tx_manager.go + const defaultGasLimit = 500000 + + beforeEach(async () => { + bigNumEquals(0, await operator.withdrawable()) + }) + + it('does not allow the oracle to withdraw the payment', async () => { + await evmRevert( + operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + { + gasLimit: 70000, + }, + ), + ), + ) + + bigNumEquals(0, await operator.withdrawable()) + }) + + it(`${defaultGasLimit} is enough to pass the gas requirement`, async () => { + await operator.connect(roles.oracleNode).fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + { + gasLimit: defaultGasLimit, + }, + ), + ) + + bigNumEquals(request.payment, await operator.withdrawable()) + }) + }) + }) + + describe('with a malicious requester', () => { + beforeEach(async () => { + const paymentAmount = toWei('1') + maliciousRequester = await maliciousRequesterFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousRequester.address, paymentAmount) + }) + + it('cannot cancel before the expiration', async () => { + await evmRevert( + maliciousRequester.maliciousRequestCancel( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ), + ) + }) + + it('cannot call functions on the LINK token through callbacks', async () => { + await evmRevert( + maliciousRequester.request( + specId, + link.address, + ethers.utils.toUtf8Bytes('transfer(address,uint256)'), + ), + ) + }) + + describe('requester lies about amount of LINK sent', () => { + it('the oracle uses the amount of LINK actually paid', async () => { + const tx = await maliciousRequester.maliciousPrice(specId) + const receipt = await tx.wait() + const req = decodeRunRequest(receipt.logs?.[3]) + + assert(toWei('1').eq(req.payment)) + }) + }) + }) + + describe('with a malicious consumer', () => { + const paymentAmount = toWei('1') + + beforeEach(async () => { + maliciousConsumer = await maliciousMultiWordConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address) + await link.transfer(maliciousConsumer.address, paymentAmount) + }) + + describe('fails during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('assertFail(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response4 = 'hack the planet 102' + const repeatedResponseValues = [ + toBytes32String(response1), + toBytes32String(response2), + toBytes32String(response4), + ] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + repeatedResponseValues, + ), + ), + ) + }) + }) + + describe('calls selfdestruct', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('doesNothing(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + await maliciousConsumer.remove() + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + }) + + describe('request is canceled during fulfillment', () => { + beforeEach(async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes( + 'cancelRequestOnFulfill(bytes32,bytes32)', + ), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + bigNumEquals(0, await link.balanceOf(maliciousConsumer.address)) + }) + + it('allows the oracle node to receive their payment', async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + const mockBalance = await link.balanceOf( + maliciousConsumer.address, + ) + bigNumEquals(mockBalance, 0) + + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(balance, 0) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), paymentAmount) + const newBalance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + bigNumEquals(paymentAmount, newBalance) + }) + + it("can't fulfill the data again", async () => { + const response4 = 'hack the planet 102' + const repeatedResponseValues = [ + toBytes32String(response1), + toBytes32String(response2), + toBytes32String(response4), + ] + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + repeatedResponseValues, + ), + ), + ) + }) + }) + + describe('tries to steal funds from node', () => { + it('is not successful with call', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthCall(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with send', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthSend(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + + it('is not successful with transfer', async () => { + const tx = await maliciousConsumer.requestData( + specId, + ethers.utils.toUtf8Bytes('stealEthTransfer(bytes32,bytes32)'), + ) + const receipt = await tx.wait() + request = decodeRunRequest(receipt.logs?.[3]) + + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest2( + ...convertFulfill2Params( + request, + responseTypes, + responseValues, + ), + ) + bigNumEquals( + 0, + await ethers.provider.getBalance(maliciousConsumer.address), + ) + }) + }) + }) + }) + }) + + describe('when the response data is too short', () => { + const response = 'Hi mom!' + const responseTypes = ['bytes32'] + const responseValues = [toBytes32String(response)] + + it('reverts', async () => { + let basicConsumer = await basicConsumerFactory + .connect(roles.defaultAccount) + .deploy(link.address, operator.address, specId) + const paymentAmount = toWei('1') + await link.transfer(basicConsumer.address, paymentAmount) + const tx = await basicConsumer.requestEthereumPrice( + 'USD', + paymentAmount, + ) + const receipt = await tx.wait() + let request = decodeRunRequest(receipt.logs?.[3]) + + const fulfillParams = convertFulfill2Params( + request, + responseTypes, + responseValues, + ) + fulfillParams[5] = '0x' // overwrite the data to be of lenght 0 + await evmRevert( + operator + .connect(roles.oracleNode) + .fulfillOracleRequest2(...fulfillParams), + 'Response must be > 32 bytes', + ) + }) + }) + }) + + describe('#withdraw', () => { + describe('without reserving funds via oracleRequest', () => { + it('does nothing', async () => { + let balance = await link.balanceOf(await roles.oracleNode.getAddress()) + assert.equal(0, balance.toNumber()) + await evmRevert( + operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), toWei('1')), + ) + balance = await link.balanceOf(await roles.oracleNode.getAddress()) + assert.equal(0, balance.toNumber()) + }) + + describe('recovering funds that were mistakenly sent', () => { + const paid = 1 + beforeEach(async () => { + await link.transfer(operator.address, paid) + }) + + it('withdraws funds', async () => { + const operatorBalanceBefore = await link.balanceOf(operator.address) + const accountBalanceBefore = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.defaultAccount.getAddress(), paid) + + const operatorBalanceAfter = await link.balanceOf(operator.address) + const accountBalanceAfter = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + const accountDifference = + accountBalanceAfter.sub(accountBalanceBefore) + const operatorDifference = + operatorBalanceBefore.sub(operatorBalanceAfter) + + bigNumEquals(operatorDifference, paid) + bigNumEquals(accountDifference, paid) + }) + }) + }) + + describe('reserving funds via oracleRequest', () => { + const payment = 15 + let request: ReturnType + + beforeEach(async () => { + const requester = await roles.defaultAccount.getAddress() + const args = encodeOracleRequest( + specId, + requester, + fHash, + 0, + constants.HashZero, + ) + const tx = await link.transferAndCall(operator.address, payment, args) + const receipt = await tx.wait() + assert.equal(3, receipt.logs?.length) + request = decodeRunRequest(receipt.logs?.[2]) + }) + + describe('but not freeing funds w fulfillOracleRequest', () => { + it('does not transfer funds', async () => { + await evmRevert( + operator + .connect(roles.defaultAccount) + .withdraw(await roles.oracleNode.getAddress(), payment), + ) + const balance = await link.balanceOf( + await roles.oracleNode.getAddress(), + ) + assert.equal(0, balance.toNumber()) + }) + + describe('recovering funds that were mistakenly sent', () => { + const paid = 1 + beforeEach(async () => { + await link.transfer(operator.address, paid) + }) + + it('withdraws funds', async () => { + const operatorBalanceBefore = await link.balanceOf(operator.address) + const accountBalanceBefore = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.defaultAccount.getAddress(), paid) + + const operatorBalanceAfter = await link.balanceOf(operator.address) + const accountBalanceAfter = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + const accountDifference = + accountBalanceAfter.sub(accountBalanceBefore) + const operatorDifference = + operatorBalanceBefore.sub(operatorBalanceAfter) + + bigNumEquals(operatorDifference, paid) + bigNumEquals(accountDifference, paid) + }) + }) + }) + + describe('and freeing funds', () => { + beforeEach(async () => { + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest( + ...convertFufillParams(request, 'Hello World!'), + ) + }) + + it('does not allow input greater than the balance', async () => { + const originalOracleBalance = await link.balanceOf(operator.address) + const originalStrangerBalance = await link.balanceOf( + await roles.stranger.getAddress(), + ) + const withdrawalAmount = payment + 1 + + assert.isAbove(withdrawalAmount, originalOracleBalance.toNumber()) + await evmRevert( + operator + .connect(roles.defaultAccount) + .withdraw(await roles.stranger.getAddress(), withdrawalAmount), + ) + + const newOracleBalance = await link.balanceOf(operator.address) + const newStrangerBalance = await link.balanceOf( + await roles.stranger.getAddress(), + ) + + assert.equal( + originalOracleBalance.toNumber(), + newOracleBalance.toNumber(), + ) + assert.equal( + originalStrangerBalance.toNumber(), + newStrangerBalance.toNumber(), + ) + }) + + it('allows transfer of partial balance by owner to specified address', async () => { + const partialAmount = 6 + const difference = payment - partialAmount + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.stranger.getAddress(), partialAmount) + const strangerBalance = await link.balanceOf( + await roles.stranger.getAddress(), + ) + const oracleBalance = await link.balanceOf(operator.address) + assert.equal(partialAmount, strangerBalance.toNumber()) + assert.equal(difference, oracleBalance.toNumber()) + }) + + it('allows transfer of entire balance by owner to specified address', async () => { + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.stranger.getAddress(), payment) + const balance = await link.balanceOf( + await roles.stranger.getAddress(), + ) + assert.equal(payment, balance.toNumber()) + }) + + it('does not allow a transfer of funds by non-owner', async () => { + await evmRevert( + operator + .connect(roles.stranger) + .withdraw(await roles.stranger.getAddress(), payment), + ) + const balance = await link.balanceOf( + await roles.stranger.getAddress(), + ) + assert.isTrue(ethers.constants.Zero.eq(balance)) + }) + + describe('recovering funds that were mistakenly sent', () => { + const paid = 1 + beforeEach(async () => { + await link.transfer(operator.address, paid) + }) + + it('withdraws funds', async () => { + const operatorBalanceBefore = await link.balanceOf(operator.address) + const accountBalanceBefore = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + await operator + .connect(roles.defaultAccount) + .withdraw(await roles.defaultAccount.getAddress(), paid) + + const operatorBalanceAfter = await link.balanceOf(operator.address) + const accountBalanceAfter = await link.balanceOf( + await roles.defaultAccount.getAddress(), + ) + + const accountDifference = + accountBalanceAfter.sub(accountBalanceBefore) + const operatorDifference = + operatorBalanceBefore.sub(operatorBalanceAfter) + + bigNumEquals(operatorDifference, paid) + bigNumEquals(accountDifference, paid) + }) + }) + }) + }) + }) + + describe('#withdrawable', () => { + let request: ReturnType + const amount = toWei('1') + + beforeEach(async () => { + const requester = await roles.defaultAccount.getAddress() + const args = encodeOracleRequest( + specId, + requester, + fHash, + 0, + constants.HashZero, + ) + const tx = await link.transferAndCall(operator.address, amount, args) + const receipt = await tx.wait() + assert.equal(3, receipt.logs?.length) + request = decodeRunRequest(receipt.logs?.[2]) + await operator + .connect(roles.oracleNode) + .fulfillOracleRequest(...convertFufillParams(request, 'Hello World!')) + }) + + it('returns the correct value', async () => { + const withdrawAmount = await operator.withdrawable() + bigNumEquals(withdrawAmount, request.payment) + }) + + describe('funds that were mistakenly sent', () => { + const paid = 1 + beforeEach(async () => { + await link.transfer(operator.address, paid) + }) + + it('returns the correct value', async () => { + const withdrawAmount = await operator.withdrawable() + + const expectedAmount = amount.add(paid) + bigNumEquals(withdrawAmount, expectedAmount) + }) + }) + }) + + describe('#ownerTransferAndCall', () => { + let operator2: Contract + let args: string + let to: string + const startingBalance = 1000 + const payment = 20 + + beforeEach(async () => { + operator2 = await operatorFactory + .connect(roles.oracleNode2) + .deploy(link.address, await roles.oracleNode2.getAddress()) + to = operator2.address + args = encodeOracleRequest( + specId, + operator.address, + operatorFactory.interface.getSighash('fulfillOracleRequest'), + 1, + constants.HashZero, + ) + }) + + describe('when called by a non-owner', () => { + it('reverts with owner error message', async () => { + await link.transfer(operator.address, startingBalance) + await evmRevert( + operator + .connect(roles.stranger) + .ownerTransferAndCall(to, payment, args), + 'Only callable by owner', + ) + }) + }) + + describe('when called by the owner', () => { + beforeEach(async () => { + await link.transfer(operator.address, startingBalance) + }) + + describe('without sufficient funds in contract', () => { + it('reverts with funds message', async () => { + const tooMuch = startingBalance * 2 + await evmRevert( + operator + .connect(roles.defaultAccount) + .ownerTransferAndCall(to, tooMuch, args), + 'Amount requested is greater than withdrawable balance', + ) + }) + }) + + describe('with sufficient funds', () => { + let tx: ContractTransaction + let receipt: ContractReceipt + let requesterBalanceBefore: BigNumber + let requesterBalanceAfter: BigNumber + let receiverBalanceBefore: BigNumber + let receiverBalanceAfter: BigNumber + + before(async () => { + requesterBalanceBefore = await link.balanceOf(operator.address) + receiverBalanceBefore = await link.balanceOf(operator2.address) + tx = await operator + .connect(roles.defaultAccount) + .ownerTransferAndCall(to, payment, args) + receipt = await tx.wait() + requesterBalanceAfter = await link.balanceOf(operator.address) + receiverBalanceAfter = await link.balanceOf(operator2.address) + }) + + it('emits an event', async () => { + assert.equal(3, receipt.logs?.length) + const transferLog = await getLog(tx, 1) + const parsedLog = link.interface.parseLog({ + data: transferLog.data, + topics: transferLog.topics, + }) + await expect(parsedLog.name).to.equal('Transfer') + }) + + it('transfers the tokens', async () => { + bigNumEquals( + requesterBalanceBefore.sub(requesterBalanceAfter), + payment, + ) + bigNumEquals(receiverBalanceAfter.sub(receiverBalanceBefore), payment) + }) + }) + }) + }) + + describe('#cancelOracleRequestByRequester', () => { + const nonce = 17 + + describe('with no pending requests', () => { + it('fails', async () => { + const fakeRequest: RunRequest = { + requestId: ethers.utils.formatBytes32String('1337'), + payment: '0', + callbackFunc: + getterSetterFactory.interface.getSighash('requestedBytes32'), + expiration: '999999999999', + + callbackAddr: '', + data: Buffer.from(''), + dataVersion: 0, + specId: '', + requester: '', + topic: '', + } + await increaseTime5Minutes(ethers.provider) + + await evmRevert( + operator + .connect(roles.stranger) + .cancelOracleRequestByRequester( + ...convertCancelByRequesterParams(fakeRequest, nonce), + ), + ) + }) + }) + + describe('with a pending request', () => { + const startingBalance = 100 + let request: ReturnType + let receipt: providers.TransactionReceipt + + beforeEach(async () => { + const requestAmount = 20 + + await link.transfer(await roles.consumer.getAddress(), startingBalance) + + const args = encodeOracleRequest( + specId, + await roles.consumer.getAddress(), + fHash, + nonce, + constants.HashZero, + ) + const tx = await link + .connect(roles.consumer) + .transferAndCall(operator.address, requestAmount, args) + receipt = await tx.wait() + + assert.equal(3, receipt.logs?.length) + request = decodeRunRequest(receipt.logs?.[2]) + + // pre conditions + const oracleBalance = await link.balanceOf(operator.address) + bigNumEquals(request.payment, oracleBalance) + + const consumerAmount = await link.balanceOf( + await roles.consumer.getAddress(), + ) + assert.equal( + startingBalance - Number(request.payment), + consumerAmount.toNumber(), + ) + }) + + describe('from a stranger', () => { + it('fails', async () => { + await evmRevert( + operator + .connect(roles.consumer) + .cancelOracleRequestByRequester( + ...convertCancelByRequesterParams(request, nonce), + ), + ) + }) + }) + + describe('from the requester', () => { + it('refunds the correct amount', async () => { + await increaseTime5Minutes(ethers.provider) + await operator + .connect(roles.consumer) + .cancelOracleRequestByRequester( + ...convertCancelByRequesterParams(request, nonce), + ) + const balance = await link.balanceOf( + await roles.consumer.getAddress(), + ) + + assert.equal(startingBalance, balance.toNumber()) // 100 + }) + + it('triggers a cancellation event', async () => { + await increaseTime5Minutes(ethers.provider) + const tx = await operator + .connect(roles.consumer) + .cancelOracleRequestByRequester( + ...convertCancelByRequesterParams(request, nonce), + ) + const receipt = await tx.wait() + + assert.equal(receipt.logs?.length, 2) + assert.equal(request.requestId, receipt.logs?.[0].topics[1]) + }) + + it('fails when called twice', async () => { + await increaseTime5Minutes(ethers.provider) + await operator + .connect(roles.consumer) + .cancelOracleRequestByRequester( + ...convertCancelByRequesterParams(request, nonce), + ) + + await evmRevert( + operator + .connect(roles.consumer) + .cancelOracleRequestByRequester(...convertCancelParams(request)), + ) + }) + }) + }) + }) + + describe('#cancelOracleRequest', () => { + describe('with no pending requests', () => { + it('fails', async () => { + const fakeRequest: RunRequest = { + requestId: ethers.utils.formatBytes32String('1337'), + payment: '0', + callbackFunc: + getterSetterFactory.interface.getSighash('requestedBytes32'), + expiration: '999999999999', + + callbackAddr: '', + data: Buffer.from(''), + dataVersion: 0, + specId: '', + requester: '', + topic: '', + } + await increaseTime5Minutes(ethers.provider) + + await evmRevert( + operator + .connect(roles.stranger) + .cancelOracleRequest(...convertCancelParams(fakeRequest)), + ) + }) + }) + + describe('with a pending request', () => { + const startingBalance = 100 + let request: ReturnType + let receipt: providers.TransactionReceipt + + beforeEach(async () => { + const requestAmount = 20 + + await link.transfer(await roles.consumer.getAddress(), startingBalance) + + const args = encodeOracleRequest( + specId, + await roles.consumer.getAddress(), + fHash, + 1, + constants.HashZero, + ) + const tx = await link + .connect(roles.consumer) + .transferAndCall(operator.address, requestAmount, args) + receipt = await tx.wait() + + assert.equal(3, receipt.logs?.length) + request = decodeRunRequest(receipt.logs?.[2]) + }) + + it('has correct initial balances', async () => { + const oracleBalance = await link.balanceOf(operator.address) + bigNumEquals(request.payment, oracleBalance) + + const consumerAmount = await link.balanceOf( + await roles.consumer.getAddress(), + ) + assert.equal( + startingBalance - Number(request.payment), + consumerAmount.toNumber(), + ) + }) + + describe('from a stranger', () => { + it('fails', async () => { + await evmRevert( + operator + .connect(roles.consumer) + .cancelOracleRequest(...convertCancelParams(request)), + ) + }) + }) + + describe('from the requester', () => { + it('refunds the correct amount', async () => { + await increaseTime5Minutes(ethers.provider) + await operator + .connect(roles.consumer) + .cancelOracleRequest(...convertCancelParams(request)) + const balance = await link.balanceOf( + await roles.consumer.getAddress(), + ) + + assert.equal(startingBalance, balance.toNumber()) // 100 + }) + + it('triggers a cancellation event', async () => { + await increaseTime5Minutes(ethers.provider) + const tx = await operator + .connect(roles.consumer) + .cancelOracleRequest(...convertCancelParams(request)) + const receipt = await tx.wait() + + assert.equal(receipt.logs?.length, 2) + assert.equal(request.requestId, receipt.logs?.[0].topics[1]) + }) + + it('fails when called twice', async () => { + await increaseTime5Minutes(ethers.provider) + await operator + .connect(roles.consumer) + .cancelOracleRequest(...convertCancelParams(request)) + + await evmRevert( + operator + .connect(roles.consumer) + .cancelOracleRequest(...convertCancelParams(request)), + ) + }) + }) + }) + }) + + describe('#ownerForward', () => { + let bytes: string + let payload: string + let mock: Contract + + beforeEach(async () => { + bytes = ethers.utils.hexlify(ethers.utils.randomBytes(100)) + payload = getterSetterFactory.interface.encodeFunctionData( + getterSetterFactory.interface.getFunction('setBytes'), + [bytes], + ) + mock = await getterSetterFactory.connect(roles.defaultAccount).deploy() + }) + + describe('when called by a non-owner', () => { + it('reverts', async () => { + await evmRevert( + operator.connect(roles.stranger).ownerForward(mock.address, payload), + ) + }) + }) + + describe('when called by owner', () => { + describe('when attempting to forward to the link token', () => { + it('reverts', async () => { + const sighash = linkTokenFactory.interface.getSighash('name') + await evmRevert( + operator + .connect(roles.defaultAccount) + .ownerForward(link.address, sighash), + 'Cannot call to LINK', + ) + }) + }) + + describe('when forwarding to any other address', () => { + it('forwards the data', async () => { + const tx = await operator + .connect(roles.defaultAccount) + .ownerForward(mock.address, payload) + await tx.wait() + assert.equal(await mock.getBytes(), bytes) + }) + + it('reverts when sending to a non-contract address', async () => { + await evmRevert( + operator + .connect(roles.defaultAccount) + .ownerForward(zeroAddress, payload), + 'Must forward to a contract', + ) + }) + + it('perceives the message is sent by the Operator', async () => { + const tx = await operator + .connect(roles.defaultAccount) + .ownerForward(mock.address, payload) + const receipt = await tx.wait() + const log: any = receipt.logs?.[0] + const logData = mock.interface.decodeEventLog( + mock.interface.getEvent('SetBytes'), + log.data, + log.topics, + ) + assert.equal(ethers.utils.getAddress(logData.from), operator.address) + }) + }) + }) + }) +}) diff --git a/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts b/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts new file mode 100644 index 00000000000..89b6d70b0a0 --- /dev/null +++ b/contracts/test/v0.8/operatorforwarder/OperatorFactory.test.ts @@ -0,0 +1,293 @@ +import { ethers } from 'hardhat' +import { evmWordToAddress, publicAbi } from '../../test-helpers/helpers' +import { assert } from 'chai' +import { Contract, ContractFactory, ContractReceipt } from 'ethers' +import { getUsers, Roles } from '../../test-helpers/setup' + +let linkTokenFactory: ContractFactory +let operatorGeneratorFactory: ContractFactory +let operatorFactory: ContractFactory +let forwarderFactory: ContractFactory + +let roles: Roles + +before(async () => { + const users = await getUsers() + + roles = users.roles + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + roles.defaultAccount, + ) + operatorGeneratorFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/OperatorFactory.sol:OperatorFactory', + roles.defaultAccount, + ) + operatorFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/Operator.sol:Operator', + roles.defaultAccount, + ) + forwarderFactory = await ethers.getContractFactory( + 'src/v0.8/operatorforwarder/dev/AuthorizedForwarder.sol:AuthorizedForwarder', + roles.defaultAccount, + ) +}) + +describe('OperatorFactory', () => { + let link: Contract + let operatorGenerator: Contract + let operator: Contract + let forwarder: Contract + let receipt: ContractReceipt + let emittedOperator: string + let emittedForwarder: string + + beforeEach(async () => { + link = await linkTokenFactory.connect(roles.defaultAccount).deploy() + operatorGenerator = await operatorGeneratorFactory + .connect(roles.defaultAccount) + .deploy(link.address) + }) + + it('has a limited public interface [ @skip-coverage ]', () => { + publicAbi(operatorGenerator, [ + 'created', + 'deployNewOperator', + 'deployNewOperatorAndForwarder', + 'deployNewForwarder', + 'deployNewForwarderAndTransferOwnership', + 'linkToken', + 'typeAndVersion', + ]) + }) + + describe('#typeAndVersion', () => { + it('describes the authorized forwarder', async () => { + assert.equal( + await operatorGenerator.typeAndVersion(), + 'OperatorFactory 1.0.0', + ) + }) + }) + + describe('#deployNewOperator', () => { + beforeEach(async () => { + const tx = await operatorGenerator + .connect(roles.oracleNode) + .deployNewOperator() + + receipt = await tx.wait() + emittedOperator = evmWordToAddress(receipt.logs?.[0].topics?.[1]) + }) + + it('emits an event', async () => { + assert.equal(receipt?.events?.[0]?.event, 'OperatorCreated') + assert.equal(emittedOperator, receipt.events?.[0].args?.[0]) + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[1], + ) + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[2], + ) + }) + + it('sets the correct owner', async () => { + operator = await operatorFactory + .connect(roles.defaultAccount) + .attach(emittedOperator) + const ownerString = await operator.owner() + assert.equal(ownerString, await roles.oracleNode.getAddress()) + }) + + it('records that it deployed that address', async () => { + assert.isTrue(await operatorGenerator.created(emittedOperator)) + }) + }) + + describe('#deployNewOperatorAndForwarder', () => { + beforeEach(async () => { + const tx = await operatorGenerator + .connect(roles.oracleNode) + .deployNewOperatorAndForwarder() + + receipt = await tx.wait() + emittedOperator = evmWordToAddress(receipt.logs?.[0].topics?.[1]) + emittedForwarder = evmWordToAddress(receipt.logs?.[3].topics?.[1]) + }) + + it('emits an event recording that the operator was deployed', async () => { + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[1], + ) + assert.equal(receipt?.events?.[0]?.event, 'OperatorCreated') + assert.equal(receipt?.events?.[0]?.args?.[0], emittedOperator) + assert.equal( + receipt?.events?.[0]?.args?.[1], + await roles.oracleNode.getAddress(), + ) + assert.equal( + receipt?.events?.[0]?.args?.[2], + await roles.oracleNode.getAddress(), + ) + }) + + it('proposes the transfer of the forwarder to the operator', async () => { + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[1], + ) + assert.equal( + receipt?.events?.[1]?.topics?.[0], + '0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278', //OwnershipTransferRequested(address,address) + ) + assert.equal( + evmWordToAddress(receipt?.events?.[1]?.topics?.[1]), + operatorGenerator.address, + ) + assert.equal( + evmWordToAddress(receipt?.events?.[1]?.topics?.[2]), + emittedOperator, + ) + + assert.equal( + receipt?.events?.[2]?.topics?.[0], + '0x4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e', //OwnershipTransferRequestedWithMessage(address,address,bytes) + ) + assert.equal( + evmWordToAddress(receipt?.events?.[2]?.topics?.[1]), + operatorGenerator.address, + ) + assert.equal( + evmWordToAddress(receipt?.events?.[2]?.topics?.[2]), + emittedOperator, + ) + }) + + it('emits an event recording that the forwarder was deployed', async () => { + assert.equal(receipt?.events?.[3]?.event, 'AuthorizedForwarderCreated') + assert.equal(receipt?.events?.[3]?.args?.[0], emittedForwarder) + assert.equal(receipt?.events?.[3]?.args?.[1], operatorGenerator.address) + assert.equal( + receipt?.events?.[3]?.args?.[2], + await roles.oracleNode.getAddress(), + ) + }) + + it('sets the correct owner on the operator', async () => { + operator = await operatorFactory + .connect(roles.defaultAccount) + .attach(receipt?.events?.[0]?.args?.[0]) + assert.equal(await roles.oracleNode.getAddress(), await operator.owner()) + }) + + it('sets the operator as the owner of the forwarder', async () => { + forwarder = await forwarderFactory + .connect(roles.defaultAccount) + .attach(emittedForwarder) + assert.equal(operatorGenerator.address, await forwarder.owner()) + }) + + it('records that it deployed that address', async () => { + assert.isTrue(await operatorGenerator.created(emittedOperator)) + assert.isTrue(await operatorGenerator.created(emittedForwarder)) + }) + }) + + describe('#deployNewForwarder', () => { + beforeEach(async () => { + const tx = await operatorGenerator + .connect(roles.oracleNode) + .deployNewForwarder() + + receipt = await tx.wait() + emittedForwarder = receipt.events?.[0].args?.[0] + }) + + it('emits an event', async () => { + assert.equal(receipt?.events?.[0]?.event, 'AuthorizedForwarderCreated') + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[1], + ) // owner + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[0].args?.[2], + ) // sender + }) + + it('sets the caller as the owner', async () => { + forwarder = await forwarderFactory + .connect(roles.defaultAccount) + .attach(emittedForwarder) + const ownerString = await forwarder.owner() + assert.equal(ownerString, await roles.oracleNode.getAddress()) + }) + + it('records that it deployed that address', async () => { + assert.isTrue(await operatorGenerator.created(emittedForwarder)) + }) + }) + + describe('#deployNewForwarderAndTransferOwnership', () => { + const message = '0x42' + + beforeEach(async () => { + const tx = await operatorGenerator + .connect(roles.oracleNode) + .deployNewForwarderAndTransferOwnership( + await roles.stranger.getAddress(), + message, + ) + receipt = await tx.wait() + + emittedForwarder = evmWordToAddress(receipt.logs?.[2].topics?.[1]) + }) + + it('emits an event', async () => { + assert.equal(receipt?.events?.[2]?.event, 'AuthorizedForwarderCreated') + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[2].args?.[1], + ) // owner + assert.equal( + await roles.oracleNode.getAddress(), + receipt.events?.[2].args?.[2], + ) // sender + }) + + it('sets the caller as the owner', async () => { + forwarder = await forwarderFactory + .connect(roles.defaultAccount) + .attach(emittedForwarder) + const ownerString = await forwarder.owner() + assert.equal(ownerString, await roles.oracleNode.getAddress()) + }) + + it('proposes a transfer to the recipient', async () => { + const emittedOwner = evmWordToAddress(receipt.logs?.[0].topics?.[1]) + assert.equal(emittedOwner, await roles.oracleNode.getAddress()) + const emittedRecipient = evmWordToAddress(receipt.logs?.[0].topics?.[2]) + assert.equal(emittedRecipient, await roles.stranger.getAddress()) + }) + + it('proposes a transfer to the recipient with the specified message', async () => { + const emittedOwner = evmWordToAddress(receipt.logs?.[1].topics?.[1]) + assert.equal(emittedOwner, await roles.oracleNode.getAddress()) + const emittedRecipient = evmWordToAddress(receipt.logs?.[1].topics?.[2]) + assert.equal(emittedRecipient, await roles.stranger.getAddress()) + + const encodedMessage = ethers.utils.defaultAbiCoder.encode( + ['bytes'], + [message], + ) + assert.equal(receipt?.logs?.[1]?.data, encodedMessage) + }) + + it('records that it deployed that address', async () => { + assert.isTrue(await operatorGenerator.created(emittedForwarder)) + }) + }) +}) diff --git a/core/bridges/external_initiator_test.go b/core/bridges/external_initiator_test.go index 923fed74f70..9f59c8e0030 100644 --- a/core/bridges/external_initiator_test.go +++ b/core/bridges/external_initiator_test.go @@ -3,6 +3,7 @@ package bridges_test import ( "testing" + "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/auth" @@ -18,8 +19,9 @@ func TestNewExternalInitiator(t *testing.T) { assert.Len(t, eia.Secret, 64) url := cltest.WebURL(t, "http://localhost:8888") + name := uuid.New().String() eir := &bridges.ExternalInitiatorRequest{ - Name: "bitcoin", + Name: name, URL: &url, } ei, err := bridges.NewExternalInitiator(eia, eir) diff --git a/core/bridges/mocks/orm.go b/core/bridges/mocks/orm.go index 1082ff84802..ba8c7526d1c 100644 --- a/core/bridges/mocks/orm.go +++ b/core/bridges/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -292,13 +292,12 @@ func (_m *ORM) UpsertBridgeResponse(dotId string, specId int32, response []byte) return r0 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/bridges/orm_test.go b/core/bridges/orm_test.go index 8034d3f05d2..db043393350 100644 --- a/core/bridges/orm_test.go +++ b/core/bridges/orm_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/google/uuid" "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -159,8 +160,9 @@ func TestORM_CreateExternalInitiator(t *testing.T) { _, orm := setupORM(t) token := auth.NewToken() + name := uuid.New().String() req := bridges.ExternalInitiatorRequest{ - Name: "externalinitiator", + Name: name, } exi, err := bridges.NewExternalInitiator(token, &req) require.NoError(t, err) @@ -175,8 +177,9 @@ func TestORM_DeleteExternalInitiator(t *testing.T) { _, orm := setupORM(t) token := auth.NewToken() + name := uuid.New().String() req := bridges.ExternalInitiatorRequest{ - Name: "externalinitiator", + Name: name, } exi, err := bridges.NewExternalInitiator(token, &req) require.NoError(t, err) diff --git a/core/build/build.go b/core/build/build.go index 027da4738f6..e7d1f7cbdca 100644 --- a/core/build/build.go +++ b/core/build/build.go @@ -1,14 +1,19 @@ +// Package build utilizes build tags and package testing API to determine the environment that this binary was built to target. +// - Prod is the default +// - Test is automatically set in test binaries, e.g. when using `go test` +// - Dev can be set with the 'dev' build tag, for standard builds or test binaries package build -// The build module utilizes build tags to determine the environment that this binary was built to target -// the currently supported build modes are dev, test. Setting both tags is not allowed and will result to compilation errors. - const ( Prod = "prod" Dev = "dev" Test = "test" ) +var mode string + +func Mode() string { return mode } + func IsDev() bool { return mode == Dev } diff --git a/core/build/default.go b/core/build/default.go deleted file mode 100644 index 81aa6b5ae3e..00000000000 --- a/core/build/default.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build !dev && !test - -package build - -const mode = Prod diff --git a/core/build/init.go b/core/build/init.go new file mode 100644 index 00000000000..a32dc4a87e2 --- /dev/null +++ b/core/build/init.go @@ -0,0 +1,13 @@ +//go:build !dev + +package build + +import "testing" + +func init() { + if testing.Testing() { + mode = Test + } else { + mode = Prod + } +} diff --git a/core/build/dev.go b/core/build/init_dev.go similarity index 53% rename from core/build/dev.go rename to core/build/init_dev.go index aadfc32fc60..a8773ef3d89 100644 --- a/core/build/dev.go +++ b/core/build/init_dev.go @@ -2,4 +2,4 @@ package build -const mode = Dev +func init() { mode = Dev } diff --git a/core/build/test.go b/core/build/test.go deleted file mode 100644 index f7758c14135..00000000000 --- a/core/build/test.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build test - -package build - -const mode = Test diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index 6323806cc1f..43ba5a4e796 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -18,16 +18,15 @@ import ( cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - + relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" "github.com/smartcontractkit/chainlink-relay/pkg/logger" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" - "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -131,8 +130,8 @@ func (c *chain) ID() string { return c.id } -func (c *chain) ChainID() relay.ChainID { - return relay.ChainID(c.id) +func (c *chain) ChainID() string { + return c.id } func (c *chain) Config() coscfg.Config { @@ -204,11 +203,9 @@ func (c *chain) Ready() error { } func (c *chain) HealthReport() map[string]error { - return map[string]error{ - c.Name(): multierr.Combine( - c.StartStopOnce.Healthy(), - c.txm.Healthy()), - } + m := map[string]error{c.Name(): c.Healthy()} + services.CopyHealth(m, c.txm.HealthReport()) + return m } // ChainService interface @@ -224,7 +221,7 @@ func (c *chain) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, err }, nil } func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return internal.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) + return relaychains.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) } func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { @@ -236,7 +233,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, stats := make([]relaytypes.NodeStatus, 0) total := len(c.cfg.Nodes) if start >= total { - return stats, total, internal.ErrOutOfRange + return stats, total, relaychains.ErrOutOfRange } if end > total { end = total diff --git a/core/chains/cosmos/config.go b/core/chains/cosmos/config.go index fda791d0dc2..8b4c8c13f32 100644 --- a/core/chains/cosmos/config.go +++ b/core/chains/cosmos/config.go @@ -3,13 +3,13 @@ package cosmos import ( "fmt" "net/url" + "slices" "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pelletier/go-toml/v2" "github.com/shopspring/decimal" "go.uber.org/multierr" - "golang.org/x/exp/slices" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" diff --git a/core/chains/cosmos/cosmostxm/orm_test.go b/core/chains/cosmos/cosmostxm/orm_test.go index 84d5cf48a20..c7418749360 100644 --- a/core/chains/cosmos/cosmostxm/orm_test.go +++ b/core/chains/cosmos/cosmostxm/orm_test.go @@ -6,13 +6,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" + + "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - - . "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" - - . "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" ) func TestORM(t *testing.T) { @@ -20,7 +19,7 @@ func TestORM(t *testing.T) { lggr := logger.TestLogger(t) logCfg := pgtest.NewQConfig(true) chainID := cosmostest.RandomChainID() - o := NewORM(chainID, db, lggr, logCfg) + o := cosmostxm.NewORM(chainID, db, lggr, logCfg) // Create mid, err := o.InsertMsg("0x123", "", []byte("hello")) @@ -28,7 +27,7 @@ func TestORM(t *testing.T) { assert.NotEqual(t, 0, int(mid)) // Read - unstarted, err := o.GetMsgsState(Unstarted, 5) + unstarted, err := o.GetMsgsState(cosmosdb.Unstarted, 5) require.NoError(t, err) require.Equal(t, 1, len(unstarted)) assert.Equal(t, "hello", string(unstarted[0].Raw)) @@ -36,21 +35,21 @@ func TestORM(t *testing.T) { t.Log(unstarted[0].UpdatedAt, unstarted[0].CreatedAt) // Limit - unstarted, err = o.GetMsgsState(Unstarted, 0) + unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 0) assert.Error(t, err) assert.Empty(t, unstarted) - unstarted, err = o.GetMsgsState(Unstarted, -1) + unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, -1) assert.Error(t, err) assert.Empty(t, unstarted) mid2, err := o.InsertMsg("0xabc", "", []byte("test")) require.NoError(t, err) assert.NotEqual(t, 0, int(mid2)) - unstarted, err = o.GetMsgsState(Unstarted, 1) + unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 1) require.NoError(t, err) require.Equal(t, 1, len(unstarted)) assert.Equal(t, "hello", string(unstarted[0].Raw)) assert.Equal(t, chainID, unstarted[0].ChainID) - unstarted, err = o.GetMsgsState(Unstarted, 2) + unstarted, err = o.GetMsgsState(cosmosdb.Unstarted, 2) require.NoError(t, err) require.Equal(t, 2, len(unstarted)) assert.Equal(t, "test", string(unstarted[1].Raw)) @@ -58,11 +57,11 @@ func TestORM(t *testing.T) { // Update txHash := "123" - err = o.UpdateMsgs([]int64{mid}, Started, &txHash) + err = o.UpdateMsgs([]int64{mid}, cosmosdb.Started, &txHash) require.NoError(t, err) - err = o.UpdateMsgs([]int64{mid}, Broadcasted, &txHash) + err = o.UpdateMsgs([]int64{mid}, cosmosdb.Broadcasted, &txHash) require.NoError(t, err) - broadcasted, err := o.GetMsgsState(Broadcasted, 5) + broadcasted, err := o.GetMsgsState(cosmosdb.Broadcasted, 5) require.NoError(t, err) require.Equal(t, 1, len(broadcasted)) assert.Equal(t, broadcasted[0].Raw, unstarted[0].Raw) @@ -70,9 +69,9 @@ func TestORM(t *testing.T) { assert.Equal(t, *broadcasted[0].TxHash, txHash) assert.Equal(t, chainID, broadcasted[0].ChainID) - err = o.UpdateMsgs([]int64{mid}, Confirmed, nil) + err = o.UpdateMsgs([]int64{mid}, cosmosdb.Confirmed, nil) require.NoError(t, err) - confirmed, err := o.GetMsgsState(Confirmed, 5) + confirmed, err := o.GetMsgsState(cosmosdb.Confirmed, 5) require.NoError(t, err) require.Equal(t, 1, len(confirmed)) } diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go index de741e8934f..e9fb2f6aca3 100644 --- a/core/chains/cosmos/cosmostxm/txm.go +++ b/core/chains/cosmos/cosmostxm/txm.go @@ -1,14 +1,16 @@ package cosmostxm import ( + "cmp" "context" "encoding/hex" + "fmt" + "slices" "strings" "time" "github.com/gogo/protobuf/proto" "github.com/pkg/errors" - "golang.org/x/exp/slices" "github.com/smartcontractkit/sqlx" @@ -176,12 +178,15 @@ func (e *msgValidator) add(msg adapters.Msg) { } func (e *msgValidator) sortValid() { - slices.SortFunc(e.valid, func(a, b adapters.Msg) bool { + slices.SortFunc(e.valid, func(a, b adapters.Msg) int { ac, bc := a.CreatedAt, b.CreatedAt if ac.Equal(bc) { - return a.ID < b.ID + return cmp.Compare(a.ID, b.ID) } - return ac.Before(bc) + if ac.After(bc) { + return 1 + } + return -1 // ac.Before(bc) }) } @@ -323,7 +328,13 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi // Assume transient api issue and retry. return err } - timeoutHeight := uint64(lb.Block.Header.Height) + uint64(txm.cfg.BlocksUntilTxTimeout()) + header, timeout := lb.SdkBlock.Header.Height, txm.cfg.BlocksUntilTxTimeout() + if header < 0 { + return fmt.Errorf("invalid negative header height: %d", header) + } else if timeout < 0 { + return fmt.Errorf("invalid negative blocks until tx timeout: %d", timeout) + } + timeoutHeight := uint64(header) + uint64(timeout) signedTx, err := tc.CreateAndSign(simResults.Succeeded.GetMsgs(), an, sn, gasLimit, txm.cfg.GasLimitMultiplier(), gasPrice, NewKeyWrapper(txm.keystoreAdapter, sender.String()), timeoutHeight) if err != nil { diff --git a/core/chains/cosmos/cosmostxm/txm_internal_test.go b/core/chains/cosmos/cosmostxm/txm_internal_test.go index 2f0b4fda06f..66a8c98b637 100644 --- a/core/chains/cosmos/cosmostxm/txm_internal_test.go +++ b/core/chains/cosmos/cosmostxm/txm_internal_test.go @@ -6,7 +6,6 @@ import ( "time" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" tmservicetypes "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" cosmostypes "github.com/cosmos/cosmos-sdk/types" txtypes "github.com/cosmos/cosmos-sdk/types/tx" @@ -16,6 +15,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" + tcmocks "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client/mocks" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + cosmosdb "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" @@ -26,11 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/utils" - - cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" - tcmocks "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client/mocks" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - . "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" ) func generateExecuteMsg(t *testing.T, msg []byte, from, to cosmostypes.AccAddress) cosmostypes.Msg { @@ -52,7 +50,7 @@ func newReaderWriterMock(t *testing.T) *tcmocks.ReaderWriter { func TestTxm(t *testing.T) { db := pgtest.NewSqlxDB(t) lggr := testutils.LoggerAssertMaxLevel(t, zapcore.ErrorLevel) - ks := keystore.New(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) require.NoError(t, ks.Unlock("blah")) for i := 0; i < 4; i++ { @@ -112,8 +110,8 @@ func TestTxm(t *testing.T) { tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ GasUsed: 1_000_000, }}, nil) - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{Block: &tmtypes.Block{ - Header: tmtypes.Header{Height: 1}, + tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ + Header: tmservicetypes.Header{Height: 1}, }}, nil) tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil) @@ -126,7 +124,7 @@ func TestTxm(t *testing.T) { completed, err := txm.ORM().GetMsgs(id1) require.NoError(t, err) require.Equal(t, 1, len(completed)) - assert.Equal(t, completed[0].State, Confirmed) + assert.Equal(t, completed[0].State, cosmosdb.Confirmed) }) t.Run("two msgs different accounts", func(t *testing.T) { @@ -168,8 +166,8 @@ func TestTxm(t *testing.T) { tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ GasUsed: 1_000_000, }}, nil).Once() - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{Block: &tmtypes.Block{ - Header: tmtypes.Header{Height: 1}, + tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ + Header: tmservicetypes.Header{Height: 1}, }}, nil).Once() tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil).Once() txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} @@ -181,8 +179,8 @@ func TestTxm(t *testing.T) { completed, err := txm.ORM().GetMsgs(id1, id2) require.NoError(t, err) require.Equal(t, 2, len(completed)) - assert.Equal(t, Errored, completed[0].State) // cancelled - assert.Equal(t, Confirmed, completed[1].State) + assert.Equal(t, cosmosdb.Errored, completed[0].State) // cancelled + assert.Equal(t, cosmosdb.Confirmed, completed[1].State) }) t.Run("two msgs different contracts", func(t *testing.T) { @@ -227,8 +225,8 @@ func TestTxm(t *testing.T) { tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ GasUsed: 1_000_000, }}, nil).Once() - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{Block: &tmtypes.Block{ - Header: tmtypes.Header{Height: 1}, + tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ + Header: tmservicetypes.Header{Height: 1}, }}, nil).Once() tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil).Once() } @@ -241,8 +239,8 @@ func TestTxm(t *testing.T) { completed, err := txm.ORM().GetMsgs(id1, id2) require.NoError(t, err) require.Equal(t, 2, len(completed)) - assert.Equal(t, Confirmed, completed[0].State) - assert.Equal(t, Confirmed, completed[1].State) + assert.Equal(t, cosmosdb.Confirmed, completed[0].State) + assert.Equal(t, cosmosdb.Confirmed, completed[1].State) }) t.Run("failed to confirm", func(t *testing.T) { @@ -257,14 +255,14 @@ func TestTxm(t *testing.T) { i, err := txm.ORM().InsertMsg("blah", "", []byte{0x01}) require.NoError(t, err) txh := "0x123" - require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, Started, &txh)) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, Broadcasted, &txh)) + require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, cosmosdb.Started, &txh)) + require.NoError(t, txm.ORM().UpdateMsgs([]int64{i}, cosmosdb.Broadcasted, &txh)) err = txm.ConfirmTx(testutils.Context(t), tc, txh, []int64{i}, 2, 1*time.Millisecond) require.NoError(t, err) m, err := txm.ORM().GetMsgs(i) require.NoError(t, err) require.Equal(t, 1, len(m)) - assert.Equal(t, Errored, m[0].State) + assert.Equal(t, cosmosdb.Errored, m[0].State) }) t.Run("confirm any unconfirmed", func(t *testing.T) { @@ -293,17 +291,17 @@ func TestTxm(t *testing.T) { require.NoError(t, err) id3, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id1}, Started, &txHash1) + err = txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Started, &txHash1) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id2}, Started, &txHash2) + err = txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Started, &txHash2) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id3}, Started, &txHash3) + err = txm.ORM().UpdateMsgs([]int64{id3}, cosmosdb.Started, &txHash3) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id1}, Broadcasted, &txHash1) + err = txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Broadcasted, &txHash1) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id2}, Broadcasted, &txHash2) + err = txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Broadcasted, &txHash2) require.NoError(t, err) - err = txm.ORM().UpdateMsgs([]int64{id3}, Broadcasted, &txHash3) + err = txm.ORM().UpdateMsgs([]int64{id3}, cosmosdb.Broadcasted, &txHash3) require.NoError(t, err) // Confirm them as in a restart while confirming scenario @@ -311,9 +309,9 @@ func TestTxm(t *testing.T) { msgs, err := txm.ORM().GetMsgs(id1, id2, id3) require.NoError(t, err) require.Equal(t, 3, len(msgs)) - assert.Equal(t, Confirmed, msgs[0].State) - assert.Equal(t, Confirmed, msgs[1].State) - assert.Equal(t, Confirmed, msgs[2].State) + assert.Equal(t, cosmosdb.Confirmed, msgs[0].State) + assert.Equal(t, cosmosdb.Confirmed, msgs[1].State) + assert.Equal(t, cosmosdb.Confirmed, msgs[2].State) }) t.Run("expired msgs", func(t *testing.T) { @@ -338,7 +336,7 @@ func TestTxm(t *testing.T) { // Should be marked errored m, err := txm.ORM().GetMsgs(id1) require.NoError(t, err) - assert.Equal(t, Errored, m[0].State) + assert.Equal(t, cosmosdb.Errored, m[0].State) // Send a batch which is all expired id2, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) @@ -350,8 +348,8 @@ func TestTxm(t *testing.T) { require.NoError(t, err) ms, err := txm.ORM().GetMsgs(id2, id3) require.NoError(t, err) - assert.Equal(t, Errored, ms[0].State) - assert.Equal(t, Errored, ms[1].State) + assert.Equal(t, cosmosdb.Errored, ms[0].State) + assert.Equal(t, cosmosdb.Errored, ms[1].State) }) t.Run("started msgs", func(t *testing.T) { @@ -360,8 +358,8 @@ func TestTxm(t *testing.T) { tc.On("SimulateUnsigned", mock.Anything, mock.Anything).Return(&txtypes.SimulateResponse{GasInfo: &cosmostypes.GasInfo{ GasUsed: 1_000_000, }}, nil) - tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{Block: &tmtypes.Block{ - Header: tmtypes.Header{Height: 1}, + tc.On("LatestBlock").Return(&tmservicetypes.GetLatestBlockResponse{SdkBlock: &tmservicetypes.Block{ + Header: tmservicetypes.Header{Height: 1}, }}, nil) tc.On("CreateAndSign", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte{0x01}, nil) txResp := &cosmostypes.TxResponse{TxHash: "4BF5122F344554C53BDE2EBB8CD2B7E3D1600AD631C385A5D7CCE23C7785459A"} @@ -379,7 +377,7 @@ func TestTxm(t *testing.T) { // Leftover started is processed msg1 := generateExecuteMsg(t, []byte{0x03}, sender1, contract) id1 := mustInsertMsg(t, txm, contract.String(), msg1) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{id1}, Started, nil)) + require.NoError(t, txm.ORM().UpdateMsgs([]int64{id1}, cosmosdb.Started, nil)) msgs := cosmosclient.SimMsgs{{ID: id1, Msg: &wasmtypes.MsgExecuteContract{ Sender: sender1.String(), Msg: []byte{0x03}, @@ -391,13 +389,13 @@ func TestTxm(t *testing.T) { txm.SendMsgBatch(testutils.Context(t)) m, err := txm.ORM().GetMsgs(id1) require.NoError(t, err) - assert.Equal(t, Confirmed, m[0].State) + assert.Equal(t, cosmosdb.Confirmed, m[0].State) // Leftover started is not cancelled msg2 := generateExecuteMsg(t, []byte{0x04}, sender1, contract) msg3 := generateExecuteMsg(t, []byte{0x05}, sender1, contract) id2 := mustInsertMsg(t, txm, contract.String(), msg2) - require.NoError(t, txm.ORM().UpdateMsgs([]int64{id2}, Started, nil)) + require.NoError(t, txm.ORM().UpdateMsgs([]int64{id2}, cosmosdb.Started, nil)) time.Sleep(time.Millisecond) // ensure != CreatedAt id3 := mustInsertMsg(t, txm, contract.String(), msg3) msgs = cosmosclient.SimMsgs{{ID: id2, Msg: &wasmtypes.MsgExecuteContract{ @@ -416,8 +414,8 @@ func TestTxm(t *testing.T) { require.NoError(t, err) ms, err := txm.ORM().GetMsgs(id2, id3) require.NoError(t, err) - assert.Equal(t, Confirmed, ms[0].State) - assert.Equal(t, Confirmed, ms[1].State) + assert.Equal(t, cosmosdb.Confirmed, ms[0].State) + assert.Equal(t, cosmosdb.Confirmed, ms[1].State) }) } diff --git a/core/chains/cosmos/cosmostxm/txm_test.go b/core/chains/cosmos/cosmostxm/txm_test.go index a3322ed2744..a7a8d0280c6 100644 --- a/core/chains/cosmos/cosmostxm/txm_test.go +++ b/core/chains/cosmos/cosmostxm/txm_test.go @@ -56,7 +56,7 @@ func TestTxm_Integration(t *testing.T) { eb := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, lggr, uuid.New()) require.NoError(t, eb.Start(testutils.Context(t))) t.Cleanup(func() { require.NoError(t, eb.Close()) }) - ks := keystore.New(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) zeConfig := sdk.GetConfig() fmt.Println(zeConfig) accounts, testdir, tendermintURL := cosmosclient.SetupLocalCosmosNode(t, chainID, *cosmosChain.GasToken) diff --git a/core/chains/cosmos/relayer_adapter.go b/core/chains/cosmos/relayer_adapter.go index ffe4181ceb0..ace441c2bb5 100644 --- a/core/chains/cosmos/relayer_adapter.go +++ b/core/chains/cosmos/relayer_adapter.go @@ -37,7 +37,7 @@ type LoopRelayerChain struct { } func NewLoopRelayerChain(r *pkgcosmos.Relayer, s adapters.Chain) *LoopRelayerChain { - ra := relay.NewRelayerServerAdapter(r, s) + ra := relay.NewServerAdapter(r, s) return &LoopRelayerChain{ Relayer: ra, chain: s, diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index 8704d0c1fc8..2646d25867b 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -8,13 +8,13 @@ import ( "net/url" "time" + gotoml "github.com/pelletier/go-toml/v2" "go.uber.org/multierr" - "golang.org/x/exp/maps" "github.com/smartcontractkit/sqlx" - gotoml "github.com/pelletier/go-toml/v2" - + relaychains "github.com/smartcontractkit/chainlink-relay/pkg/chains" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" @@ -30,10 +30,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/internal" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -65,7 +63,6 @@ var ( // LegacyChains implements [LegacyChainContainer] type LegacyChains struct { *chains.ChainsKV[Chain] - dflt Chain cfgs toml.EVMConfigs } @@ -250,7 +247,16 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod if opts.GenLogPoller != nil { logPoller = opts.GenLogPoller(chainID) } else { - logPoller = logpoller.NewObservedLogPoller(logpoller.NewORM(chainID, db, l, cfg.Database()), client, l, cfg.EVM().LogPollInterval(), int64(cfg.EVM().FinalityDepth()), int64(cfg.EVM().LogBackfillBatchSize()), int64(cfg.EVM().RPCDefaultBatchSize()), int64(cfg.EVM().LogKeepBlocksDepth())) + logPoller = logpoller.NewLogPoller( + logpoller.NewObservedORM(chainID, db, l, cfg.Database()), + client, + l, + cfg.EVM().LogPollInterval(), + cfg.EVM().FinalityTagEnabled(), + int64(cfg.EVM().FinalityDepth()), + int64(cfg.EVM().LogBackfillBatchSize()), + int64(cfg.EVM().RPCDefaultBatchSize()), + int64(cfg.EVM().LogKeepBlocksDepth())) } } @@ -377,16 +383,14 @@ func (c *chain) Name() string { } func (c *chain) HealthReport() map[string]error { - report := map[string]error{ - c.Name(): c.StartStopOnce.Healthy(), - } - maps.Copy(report, c.txm.HealthReport()) - maps.Copy(report, c.headBroadcaster.HealthReport()) - maps.Copy(report, c.headTracker.HealthReport()) - maps.Copy(report, c.logBroadcaster.HealthReport()) + report := map[string]error{c.Name(): c.Healthy()} + services.CopyHealth(report, c.txm.HealthReport()) + services.CopyHealth(report, c.headBroadcaster.HealthReport()) + services.CopyHealth(report, c.headTracker.HealthReport()) + services.CopyHealth(report, c.logBroadcaster.HealthReport()) if c.balanceMonitor != nil { - maps.Copy(report, c.balanceMonitor.HealthReport()) + services.CopyHealth(report, c.balanceMonitor.HealthReport()) } return report @@ -417,7 +421,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]types.NodeStatus, int, error nodes := c.cfg.Nodes() total := len(nodes) if start >= total { - return nil, total, internal.ErrOutOfRange + return nil, total, relaychains.ErrOutOfRange } if end > total { end = total @@ -454,7 +458,7 @@ func (c *chain) listNodeStatuses(start, end int) ([]types.NodeStatus, int, error } func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { - return internal.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) + return relaychains.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) } func (c *chain) ID() *big.Int { return c.id } @@ -484,7 +488,7 @@ func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Dura primaries = append(primaries, primary) } } - return evmclient.NewClientWithNodes(lggr, cfg.SelectionMode(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) + return evmclient.NewClientWithNodes(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType) } func newPrimary(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, n *toml.Node, id int32, chainID *big.Int) (evmclient.Node, error) { diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 339542f4ce1..3a3b8b23a92 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -108,8 +108,8 @@ var _ htrktypes.Client[*evmtypes.Head, ethereum.Subscription, *big.Int, common.H // NewClientWithNodes instantiates a client from a list of nodes // Currently only supports one primary -func NewClientWithNodes(logger logger.Logger, selectionMode string, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { - pool := NewPool(logger, selectionMode, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) +func NewClientWithNodes(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { + pool := NewPool(logger, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) return &client{ logger: logger, pool: pool, diff --git a/core/chains/evm/client/erroring_node.go b/core/chains/evm/client/erroring_node.go index 152b52a7acb..21c4d269ea4 100644 --- a/core/chains/evm/client/erroring_node.go +++ b/core/chains/evm/client/erroring_node.go @@ -20,6 +20,12 @@ type erroringNode struct { errMsg string } +func (e *erroringNode) UnsubscribeAllExceptAliveLoop() {} + +func (e *erroringNode) SubscribersCount() int32 { + return 0 +} + func (e *erroringNode) ChainID() (chainID *big.Int) { return nil } func (e *erroringNode) Start(ctx context.Context) error { return errors.New(e.errMsg) } diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 8a660eb38db..342a9143432 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -19,12 +19,16 @@ type TestNodePoolConfig struct { NodePollInterval time.Duration NodeSelectionMode string NodeSyncThreshold uint32 + NodeLeaseDuration time.Duration } func (tc TestNodePoolConfig) PollFailureThreshold() uint32 { return tc.NodePollFailureThreshold } func (tc TestNodePoolConfig) PollInterval() time.Duration { return tc.NodePollInterval } func (tc TestNodePoolConfig) SelectionMode() string { return tc.NodeSelectionMode } func (tc TestNodePoolConfig) SyncThreshold() uint32 { return tc.NodeSyncThreshold } +func (tc TestNodePoolConfig) LeaseDuration() time.Duration { + return tc.NodeLeaseDuration +} func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeadsThreshold time.Duration, rpcUrl string, rpcHTTPURL *url.URL, sendonlyRPCURLs []url.URL, id int32, chainID *big.Int) (*client, error) { parsed, err := url.ParseRequestURI(rpcUrl) @@ -50,7 +54,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads sendonlys = append(sendonlys, s) } - pool := NewPool(lggr, nodePoolCfg.SelectionMode(), noNewHeadsThreshold, primaries, sendonlys, chainID, "") + pool := NewPool(lggr, nodePoolCfg.SelectionMode(), nodePoolCfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, "") c := &client{logger: lggr, pool: pool} t.Cleanup(c.Close) return c, nil diff --git a/core/chains/evm/client/mocks/batch_sender.go b/core/chains/evm/client/mocks/batch_sender.go index bd7653e62f6..7f1a5bdee69 100644 --- a/core/chains/evm/client/mocks/batch_sender.go +++ b/core/chains/evm/client/mocks/batch_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -28,13 +28,12 @@ func (_m *BatchSender) BatchCallContext(ctx context.Context, b []rpc.BatchElem) return r0 } -type mockConstructorTestingTNewBatchSender interface { +// NewBatchSender creates a new instance of BatchSender. 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 NewBatchSender(t interface { mock.TestingT Cleanup(func()) -} - -// NewBatchSender creates a new instance of BatchSender. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBatchSender(t mockConstructorTestingTNewBatchSender) *BatchSender { +}) *BatchSender { mock := &BatchSender{} mock.Mock.Test(t) diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index aec16a9e524..fdcb15d6a63 100644 --- a/core/chains/evm/client/mocks/client.go +++ b/core/chains/evm/client/mocks/client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -795,13 +795,12 @@ func (_m *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* return r0, r1 } -type mockConstructorTestingTNewClient interface { +// NewClient creates a new instance of Client. 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 NewClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewClient(t mockConstructorTestingTNewClient) *Client { +}) *Client { mock := &Client{} mock.Mock.Test(t) diff --git a/core/chains/evm/client/mocks/tx_sender.go b/core/chains/evm/client/mocks/tx_sender.go index 186aa8f8ebf..889069dcfca 100644 --- a/core/chains/evm/client/mocks/tx_sender.go +++ b/core/chains/evm/client/mocks/tx_sender.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -57,13 +57,12 @@ func (_m *TxSender) SendTransaction(ctx context.Context, tx *types.Transaction) return r0 } -type mockConstructorTestingTNewTxSender interface { +// NewTxSender creates a new instance of TxSender. 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 NewTxSender(t interface { mock.TestingT Cleanup(func()) -} - -// NewTxSender creates a new instance of TxSender. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTxSender(t mockConstructorTestingTNewTxSender) *TxSender { +}) *TxSender { mock := &TxSender{} mock.Mock.Test(t) diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index 84344a5a076..4f7132a6cc4 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -94,6 +94,8 @@ type Node interface { Name() string ChainID() *big.Int Order() int32 + SubscribersCount() int32 + UnsubscribeAllExceptAliveLoop() CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error BatchCallContext(ctx context.Context, b []rpc.BatchElem) error @@ -153,6 +155,9 @@ type node struct { // close the underlying subscription subs []ethereum.Subscription + // Need to track the aliveLoop subscription, so we do not cancel it when checking lease + aliveLoopSub ethereum.Subscription + // chStopInFlight can be closed to immediately cancel all in-flight requests on // this node. Closing and replacing should be serialized through // stateMu since it can happen on state transitions as well as node Close. @@ -380,6 +385,26 @@ func (n *node) disconnectAll() { n.unsubscribeAll() } +// SubscribersCount returns the number of client subscribed to the node +func (n *node) SubscribersCount() int32 { + n.stateMu.RLock() + defer n.stateMu.RUnlock() + return int32(len(n.subs)) +} + +// UnsubscribeAllExceptAliveLoop disconnects all subscriptions to the node except the alive loop subscription +// while holding the n.stateMu lock +func (n *node) UnsubscribeAllExceptAliveLoop() { + n.stateMu.Lock() + defer n.stateMu.Unlock() + + for _, s := range n.subs { + if s != n.aliveLoopSub { + s.Unsubscribe() + } + } +} + // cancelInflightRequests closes and replaces the chStopInFlight // WARNING: NOT THREAD-SAFE // This must be called from within the n.stateMu lock diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index d55df58d6ef..609d1522ea5 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -97,6 +97,7 @@ func (n *node) aliveLoop() { n.declareUnreachable() return } + n.aliveLoopSub = sub defer sub.Unsubscribe() var outOfSyncT *time.Ticker diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index f9dca7e9cf8..7e4667623de 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -51,6 +51,7 @@ type NodeSelector interface { type PoolConfig interface { NodeSelectionMode() string NodeNoNewHeadsThreshold() time.Duration + LeaseDuration() time.Duration } // Pool represents an abstraction over one or more primary nodes @@ -65,6 +66,8 @@ type Pool struct { selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector + leaseDuration time.Duration + leaseTicker *time.Ticker activeMu sync.RWMutex activeNode Node @@ -73,7 +76,7 @@ type Pool struct { wg sync.WaitGroup } -func NewPool(logger logger.Logger, selectionMode string, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool { +func NewPool(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool { if chainID == nil { panic("chainID is required") } @@ -105,6 +108,7 @@ func NewPool(logger logger.Logger, selectionMode string, noNewHeadsTreshold time noNewHeadsThreshold: noNewHeadsTreshold, nodeSelector: nodeSelector, chStop: make(chan struct{}), + leaseDuration: leaseDuration, } p.logger.Debugf("The pool is configured to use NodeSelectionMode: %s", selectionMode) @@ -150,6 +154,14 @@ func (p *Pool) Dial(ctx context.Context) error { p.wg.Add(1) go p.runLoop() + if p.leaseDuration.Seconds() > 0 && p.selectionMode != NodeSelectionMode_RoundRobin { + p.logger.Infof("The pool will switch to best node every %s", p.leaseDuration.String()) + p.wg.Add(1) + go p.checkLeaseLoop() + } else { + p.logger.Info("Best node switching is disabled") + } + return nil }) } @@ -172,6 +184,39 @@ func (p *Pool) nLiveNodes() (nLiveNodes int, blockNumber int64, totalDifficulty return } +func (p *Pool) checkLease() { + bestNode := p.nodeSelector.Select() + for _, n := range p.nodes { + // Terminate client subscriptions. Services are responsible for reconnecting, which will be routed to the new + // best node. Only terminate connections with more than 1 subscription to account for the aliveLoop subscription + if n.State() == NodeStateAlive && n != bestNode && n.SubscribersCount() > 1 { + p.logger.Infof("Switching to best node from %q to %q", n.String(), bestNode.String()) + n.UnsubscribeAllExceptAliveLoop() + } + } + + if bestNode != p.activeNode { + p.activeMu.Lock() + p.activeNode = bestNode + p.activeMu.Unlock() + } +} + +func (p *Pool) checkLeaseLoop() { + defer p.wg.Done() + p.leaseTicker = time.NewTicker(p.leaseDuration) + defer p.leaseTicker.Stop() + + for { + select { + case <-p.leaseTicker.C: + p.checkLease() + case <-p.chStop: + return + } + } +} + func (p *Pool) runLoop() { defer p.wg.Done() @@ -271,6 +316,9 @@ func (p *Pool) selectNode() (node Node) { return &erroringNode{errMsg: errmsg.Error()} } + if p.leaseTicker != nil { + p.leaseTicker.Reset(p.leaseDuration) + } return p.activeNode } @@ -317,7 +365,7 @@ func (p *Pool) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error return main.BatchCallContext(ctx, b) } -// Wrapped Geth client methods +// SendTransaction wrapped Geth client methods func (p *Pool) SendTransaction(ctx context.Context, tx *types.Transaction) error { main := p.selectNode() var all []SendOnlyNode diff --git a/core/chains/evm/client/pool_test.go b/core/chains/evm/client/pool_test.go index 00c42597c36..15a6484756d 100644 --- a/core/chains/evm/client/pool_test.go +++ b/core/chains/evm/client/pool_test.go @@ -5,6 +5,7 @@ import ( "math/big" "net/http/httptest" "net/url" + "sync" "testing" "time" @@ -27,6 +28,7 @@ import ( type poolConfig struct { selectionMode string noNewHeadsThreshold time.Duration + leaseDuration time.Duration } func (c poolConfig) NodeSelectionMode() string { @@ -37,9 +39,14 @@ func (c poolConfig) NodeNoNewHeadsThreshold() time.Duration { return c.noNewHeadsThreshold } +func (c poolConfig) LeaseDuration() time.Duration { + return c.leaseDuration +} + var defaultConfig evmclient.PoolConfig = &poolConfig{ selectionMode: evmclient.NodeSelectionMode_RoundRobin, noNewHeadsThreshold: 0, + leaseDuration: time.Second * 0, } func TestPool_Dial(t *testing.T) { @@ -157,7 +164,7 @@ func TestPool_Dial(t *testing.T) { for i, n := range test.sendNodes { sendNodes[i] = n.newSendOnlyNode(t, test.sendNodeChainID) } - p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), time.Second*0, nodes, sendNodes, test.poolChainID, "") + p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendNodes, test.poolChainID, "") err := p.Dial(ctx) if err == nil { t.Cleanup(func() { assert.NoError(t, p.Close()) }) @@ -250,7 +257,7 @@ func TestUnit_Pool_RunLoop(t *testing.T) { nodes := []evmclient.Node{n1, n2, n3} lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) - p := evmclient.NewPool(lggr, defaultConfig.NodeSelectionMode(), time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "") + p := evmclient.NewPool(lggr, defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "") n1.On("String").Maybe().Return("n1") n2.On("String").Maybe().Return("n2") @@ -324,9 +331,66 @@ func TestUnit_Pool_BatchCallContextAll(t *testing.T) { sendonlys = append(sendonlys, s) } - p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), time.Second*0, nodes, sendonlys, &cltest.FixtureChainID, "") + p := evmclient.NewPool(logger.TestLogger(t), defaultConfig.NodeSelectionMode(), defaultConfig.LeaseDuration(), time.Second*0, nodes, sendonlys, &cltest.FixtureChainID, "") assert.True(t, p.ChainType().IsValid()) assert.False(t, p.ChainType().IsL2()) require.NoError(t, p.BatchCallContextAll(ctx, b)) } + +func TestUnit_Pool_LeaseDuration(t *testing.T) { + t.Parallel() + + n1 := evmmocks.NewNode(t) + n2 := evmmocks.NewNode(t) + nodes := []evmclient.Node{n1, n2} + type nodeStateSwitch struct { + isAlive bool + mu sync.RWMutex + } + + nodeSwitch := nodeStateSwitch{ + isAlive: true, + mu: sync.RWMutex{}, + } + + n1.On("String").Maybe().Return("n1") + n2.On("String").Maybe().Return("n2") + n1.On("Close").Maybe().Return(nil) + n2.On("Close").Maybe().Return(nil) + n2.On("UnsubscribeAllExceptAliveLoop").Return() + n2.On("SubscribersCount").Return(int32(2)) + + n1.On("Start", mock.Anything).Return(nil).Once() + n1.On("State").Return(func() evmclient.NodeState { + nodeSwitch.mu.RLock() + defer nodeSwitch.mu.RUnlock() + if nodeSwitch.isAlive { + return evmclient.NodeStateAlive + } + return evmclient.NodeStateOutOfSync + }) + n1.On("Order").Return(int32(1)) + n1.On("ChainID").Return(testutils.FixtureChainID).Once() + + n2.On("Start", mock.Anything).Return(nil).Once() + n2.On("State").Return(evmclient.NodeStateAlive) + n2.On("Order").Return(int32(2)) + n2.On("ChainID").Return(testutils.FixtureChainID).Once() + + lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + p := evmclient.NewPool(lggr, "PriorityLevel", time.Second*2, time.Second*0, nodes, []evmclient.SendOnlyNode{}, &cltest.FixtureChainID, "") + require.NoError(t, p.Dial(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, p.Close()) }) + + testutils.WaitForLogMessage(t, observedLogs, "The pool will switch to best node every 2s") + nodeSwitch.mu.Lock() + nodeSwitch.isAlive = false + nodeSwitch.mu.Unlock() + testutils.WaitForLogMessage(t, observedLogs, "At least one EVM primary node is dead") + nodeSwitch.mu.Lock() + nodeSwitch.isAlive = true + nodeSwitch.mu.Unlock() + testutils.WaitForLogMessage(t, observedLogs, `Switching to best node from "n2" to "n1"`) + +} diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index dd79c549bfe..abab2046620 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -545,7 +545,7 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B if len(elem.Args) != 2 { return fmt.Errorf("SimulatedBackendClient expected 2 args, got %d for eth_getBlockByNumber", len(elem.Args)) } - blockNum, is := elem.Args[0].(string) + blockNumOrTag, is := elem.Args[0].(string) if !is { return fmt.Errorf("SimulatedBackendClient expected first arg to be a string for eth_getBlockByNumber, got: %T", elem.Args[0]) } @@ -553,31 +553,24 @@ func (c *SimulatedBackendClient) BatchCallContext(ctx context.Context, b []rpc.B if !is { return fmt.Errorf("SimulatedBackendClient expected second arg to be a boolean for eth_getBlockByNumber, got: %T", elem.Args[1]) } - n, ok := new(big.Int).SetString(blockNum, 0) - if !ok { - return fmt.Errorf("error while converting block number string: %s to big.Int ", blockNum) - } - header, err := c.b.HeaderByNumber(ctx, n) + header, err := c.fetchHeader(ctx, blockNumOrTag) if err != nil { return err } - switch v := elem.Result.(type) { + switch res := elem.Result.(type) { case *evmtypes.Head: - b[i].Result = &evmtypes.Head{ - Number: header.Number.Int64(), - Hash: header.Hash(), - Timestamp: time.Unix(int64(header.Time), 0).UTC(), - } + res.Number = header.Number.Int64() + res.Hash = header.Hash() + res.ParentHash = header.ParentHash + res.Timestamp = time.Unix(int64(header.Time), 0).UTC() case *evmtypes.Block: - b[i].Result = &evmtypes.Block{ - Number: header.Number.Int64(), - Hash: header.Hash(), - Timestamp: time.Unix(int64(header.Time), 0), - } + res.Number = header.Number.Int64() + res.Hash = header.Hash() + res.ParentHash = header.ParentHash + res.Timestamp = time.Unix(int64(header.Time), 0).UTC() default: - return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", v) + return fmt.Errorf("SimulatedBackendClient Unexpected Type %T", elem.Result) } - b[i].Error = err case "eth_call": if len(elem.Args) != 2 { @@ -718,3 +711,20 @@ func toCallMsg(params map[string]interface{}) ethereum.CallMsg { func (c *SimulatedBackendClient) IsL2() bool { return false } + +func (c *SimulatedBackendClient) fetchHeader(ctx context.Context, blockNumOrTag string) (*types.Header, error) { + switch blockNumOrTag { + case rpc.SafeBlockNumber.String(): + return c.b.Blockchain().CurrentSafeBlock(), nil + case rpc.LatestBlockNumber.String(): + return c.b.Blockchain().CurrentHeader(), nil + case rpc.FinalizedBlockNumber.String(): + return c.b.Blockchain().CurrentFinalBlock(), nil + default: + blockNum, ok := new(big.Int).SetString(blockNumOrTag, 0) + if !ok { + return nil, fmt.Errorf("error while converting block number string: %s to big.Int ", blockNumOrTag) + } + return c.b.HeaderByNumber(ctx, blockNum) + } +} diff --git a/core/chains/evm/config/chain_scoped_node_pool.go b/core/chains/evm/config/chain_scoped_node_pool.go index 2f26aaab0c7..8244d620a53 100644 --- a/core/chains/evm/config/chain_scoped_node_pool.go +++ b/core/chains/evm/config/chain_scoped_node_pool.go @@ -25,3 +25,7 @@ func (n *nodePoolConfig) SelectionMode() string { func (n *nodePoolConfig) SyncThreshold() uint32 { return *n.c.SyncThreshold } + +func (n *nodePoolConfig) LeaseDuration() time.Duration { + return n.c.LeaseDuration.Duration() +} diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index 18c075dc24a..f8ec030969e 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -125,6 +125,7 @@ type NodePool interface { PollInterval() time.Duration SelectionMode() string SyncThreshold() uint32 + LeaseDuration() time.Duration } // TODO BCF-2509 does the chainscopedconfig really need the entire app config? diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index b8347f6e4bb..cb18282f495 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -252,9 +252,9 @@ func (_m *ChainScopedConfig) Log() coreconfig.Log { return r0 } -// LogConfiguration provides a mock function with given fields: log -func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn) { - _m.Called(log) +// LogConfiguration provides a mock function with given fields: log, warn +func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn, warn coreconfig.LogfFn) { + _m.Called(log, warn) } // Mercury provides a mock function with given fields: @@ -497,6 +497,22 @@ func (_m *ChainScopedConfig) Threshold() coreconfig.Threshold { return r0 } +// Tracing provides a mock function with given fields: +func (_m *ChainScopedConfig) Tracing() coreconfig.Tracing { + ret := _m.Called() + + var r0 coreconfig.Tracing + if rf, ok := ret.Get(0).(func() coreconfig.Tracing); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(coreconfig.Tracing) + } + } + + return r0 +} + // Validate provides a mock function with given fields: func (_m *ChainScopedConfig) Validate() error { ret := _m.Called() @@ -541,13 +557,12 @@ func (_m *ChainScopedConfig) WebServer() coreconfig.WebServer { return r0 } -type mockConstructorTestingTNewChainScopedConfig interface { +// NewChainScopedConfig creates a new instance of ChainScopedConfig. 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 NewChainScopedConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewChainScopedConfig creates a new instance of ChainScopedConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewChainScopedConfig(t mockConstructorTestingTNewChainScopedConfig) *ChainScopedConfig { +}) *ChainScopedConfig { mock := &ChainScopedConfig{} mock.Mock.Test(t) diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index 0788370d3cc..8cb54132f58 100644 --- a/core/chains/evm/config/mocks/gas_estimator.go +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -302,13 +302,12 @@ func (_m *GasEstimator) TipCapMin() *assets.Wei { return r0 } -type mockConstructorTestingTNewGasEstimator interface { +// NewGasEstimator creates a new instance of GasEstimator. 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 NewGasEstimator(t interface { mock.TestingT Cleanup(func()) -} - -// NewGasEstimator creates a new instance of GasEstimator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewGasEstimator(t mockConstructorTestingTNewGasEstimator) *GasEstimator { +}) *GasEstimator { mock := &GasEstimator{} mock.Mock.Test(t) diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index a62c554a21e..cf2cde460e5 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -3,13 +3,13 @@ package toml import ( "fmt" "net/url" + "slices" "strconv" "github.com/ethereum/go-ethereum/core/txpool" "github.com/pelletier/go-toml/v2" "github.com/shopspring/decimal" "go.uber.org/multierr" - "golang.org/x/exp/slices" "gopkg.in/guregu/null.v4" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" @@ -689,6 +689,7 @@ type NodePool struct { PollInterval *models.Duration SelectionMode *string SyncThreshold *uint32 + LeaseDuration *models.Duration } func (p *NodePool) setFrom(f *NodePool) { @@ -704,6 +705,9 @@ func (p *NodePool) setFrom(f *NodePool) { if v := f.SyncThreshold; v != nil { p.SyncThreshold = v } + if v := f.LeaseDuration; v != nil { + p.LeaseDuration = v + } } type OCR struct { diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index 239a97f585b..68513383585 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -5,10 +5,9 @@ import ( "embed" "log" "path/filepath" + "slices" "strings" - "golang.org/x/exp/slices" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/utils" configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" @@ -62,8 +61,8 @@ func init() { defaults[id] = config.Chain defaultNames[id] = strings.ReplaceAll(strings.TrimSuffix(fe.Name(), ".toml"), "_", " ") } - slices.SortFunc(DefaultIDs, func(a, b *utils.Big) bool { - return a.Cmp(b) < 0 + slices.SortFunc(DefaultIDs, func(a, b *utils.Big) int { + return a.Cmp(b) }) } diff --git a/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml b/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml new file mode 100644 index 00000000000..e26a137d2ba --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Arbitrum_Sepolia.toml @@ -0,0 +1,26 @@ +ChainID = '421614' +ChainType = 'arbitrum' +NoNewHeadsThreshold = '0' +OCR.ContractConfirmations = 1 +LogPollInterval = '1s' + +[GasEstimator] +Mode = 'Arbitrum' +LimitMax = 1_000_000_000 +# Arbitrum uses the suggested gas price, so we don't want to place any limits on the minimum +PriceMin = '0' +PriceDefault = '0.1 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +FeeCapDefault = '1000 gwei' +# Disable gas bumping on arbitrum +BumpThreshold = 0 + +[GasEstimator.BlockHistory] +# Force an error if someone set GAS_UPDATER_ENABLED=true by accident; we never want to run the block history estimator on arbitrum +BlockHistorySize = 0 + +[NodePool] +SyncThreshold = 10 + +[OCR2.Automation] +GasLimit = 14500000 diff --git a/core/chains/evm/config/toml/defaults/Linea_Goerli.toml b/core/chains/evm/config/toml/defaults/Linea_Goerli.toml new file mode 100644 index 00000000000..915727267d2 --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Linea_Goerli.toml @@ -0,0 +1,12 @@ +ChainID = '59140' +# Block time 12s, finality < 3m +FinalityDepth = 15 +# Blocks are only emitted when a transaction happens / no empty blocks +NoNewHeadsThreshold = '0' + +[GasEstimator] +BumpPercent = 40 + +[Transactions] +# increase resend time to align with finality +ResendAfterThreshold = '3m' diff --git a/core/chains/evm/config/toml/defaults/Linea_Mainnet.toml b/core/chains/evm/config/toml/defaults/Linea_Mainnet.toml new file mode 100644 index 00000000000..94d8bedc44b --- /dev/null +++ b/core/chains/evm/config/toml/defaults/Linea_Mainnet.toml @@ -0,0 +1,17 @@ +ChainID = '59144' +# Block time 12s, finality < 60m +FinalityDepth = 300 +# Blocks are only emitted when a transaction happens / no empty blocks +NoNewHeadsThreshold = '0' + +[GasEstimator] +BumpPercent = 40 +PriceMin = '400 mwei' + +[Transactions] +# increase resend time to align with finality +ResendAfterThreshold = '3m' + +# set greater than finality depth +[HeadTracker] +HistoryDepth = 350 diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml index a0c4f9b4c6b..a75cfa0bf3b 100644 --- a/core/chains/evm/config/toml/defaults/fallback.toml +++ b/core/chains/evm/config/toml/defaults/fallback.toml @@ -58,6 +58,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index 80b8b3d8b94..0c470e76d8c 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -253,7 +253,7 @@ func (f *FwdMgr) runLoop() { f.latestBlock, []common.Hash{authChangedTopic}, addrs, - int(f.cfg.FinalityDepth()), + evmlogpoller.Confirmations(f.cfg.FinalityDepth()), pg.WithParentCtx(f.ctx), ) if err != nil { @@ -322,5 +322,5 @@ func (f *FwdMgr) Close() error { } func (f *FwdMgr) HealthReport() map[string]error { - return map[string]error{f.Name(): f.StartStopOnce.Healthy()} + return map[string]error{f.Name(): f.Healthy()} } diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index bcbe43ef9b6..0117c2f2c07 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -58,7 +58,7 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { t.Log(authorized) evmClient := client.NewSimulatedBackendClient(t, ec, testutils.FixtureChainID) - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, 2, 3, 2, 1000) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) @@ -111,7 +111,7 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { ec.Commit() evmClient := client.NewSimulatedBackendClient(t, ec, testutils.FixtureChainID) - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, 2, 3, 2, 1000) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), evmClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.TestLogger(t), cfg.Database()) diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index 5515e6a1506..e8ab62ce7de 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -140,13 +140,12 @@ func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common. return r0, r1 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index df0c4b8f8cb..6c2b5e8b879 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -5,13 +5,15 @@ import ( "fmt" "math" "math/big" + "slices" "sync" "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "golang.org/x/exp/slices" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -92,7 +94,9 @@ func (a *arbitrumEstimator) Close() error { func (a *arbitrumEstimator) Ready() error { return a.StartStopOnce.Ready() } func (a *arbitrumEstimator) HealthReport() map[string]error { - return map[string]error{a.Name(): a.StartStopOnce.Healthy()} + hp := map[string]error{a.Name(): a.Healthy()} + services.CopyHealth(hp, a.EvmEstimator.HealthReport()) + return hp } // GetLegacyGas estimates both the gas price and the gas limit. diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go index 556c0b1715c..14b18ad66ba 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -243,7 +243,7 @@ func (b *BlockHistoryEstimator) Name() string { return b.logger.Name() } func (b *BlockHistoryEstimator) HealthReport() map[string]error { - return map[string]error{b.Name(): b.StartStopOnce.Healthy()} + return map[string]error{b.Name(): b.Healthy()} } func (b *BlockHistoryEstimator) GetLegacyGas(_ context.Context, _ []byte, gasLimit uint32, maxGasPriceWei *assets.Wei, _ ...feetypes.Opt) (gasPrice *assets.Wei, chainSpecificGasLimit uint32, err error) { diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index e418e0d6873..7f4d157e37a 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -108,21 +108,21 @@ func TestBlockHistoryEstimator_Start(t *testing.T) { }) t.Run("starts and loads partial history if fetch context times out", func(t *testing.T) { - geCfg := &gas.MockGasEstimatorConfig{} - geCfg.EIP1559DynamicFeesF = true - geCfg.LimitMultiplierF = float32(1) - geCfg.PriceMinF = minGasPrice - - bhCfg := newBlockHistoryConfig() - bhCfg.BatchSizeF = uint32(1) - bhCfg.BlockDelayF = blockDelay - bhCfg.BlockHistorySizeF = historySize - bhCfg.TransactionPercentileF = percentile - - cfg := gas.NewMockConfig() + geCfg2 := &gas.MockGasEstimatorConfig{} + geCfg2.EIP1559DynamicFeesF = true + geCfg2.LimitMultiplierF = float32(1) + geCfg2.PriceMinF = minGasPrice + + bhCfg2 := newBlockHistoryConfig() + bhCfg2.BatchSizeF = uint32(1) + bhCfg2.BlockDelayF = blockDelay + bhCfg2.BlockHistorySizeF = historySize + bhCfg2.TransactionPercentileF = percentile + + cfg2 := gas.NewMockConfig() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - bhe := newBlockHistoryEstimator(t, ethClient, cfg, geCfg, bhCfg) + bhe := newBlockHistoryEstimator(t, ethClient, cfg2, geCfg2, bhCfg2) h := &evmtypes.Head{Hash: utils.NewHash(), Number: 42, BaseFeePerGas: assets.NewWeiI(420)} ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(h, nil) diff --git a/core/chains/evm/gas/fixed_price_estimator.go b/core/chains/evm/gas/fixed_price_estimator.go index 733dd179fec..a45df741a27 100644 --- a/core/chains/evm/gas/fixed_price_estimator.go +++ b/core/chains/evm/gas/fixed_price_estimator.go @@ -4,6 +4,7 @@ import ( "context" "github.com/pkg/errors" + commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/assets" diff --git a/core/chains/evm/gas/l2_suggested_estimator.go b/core/chains/evm/gas/l2_suggested_estimator.go index e59eca2b064..1782e349302 100644 --- a/core/chains/evm/gas/l2_suggested_estimator.go +++ b/core/chains/evm/gas/l2_suggested_estimator.go @@ -2,12 +2,12 @@ package gas import ( "context" + "slices" "sync" "time" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "golang.org/x/exp/slices" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -76,7 +76,7 @@ func (o *l2SuggestedPriceEstimator) Close() error { } func (o *l2SuggestedPriceEstimator) HealthReport() map[string]error { - return map[string]error{o.Name(): o.StartStopOnce.Healthy()} + return map[string]error{o.Name(): o.Healthy()} } func (o *l2SuggestedPriceEstimator) run() { diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index 8cbc4832986..eabbd0f03e4 100644 --- a/core/chains/evm/gas/mocks/config.go +++ b/core/chains/evm/gas/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -55,13 +55,12 @@ func (_m *Config) FinalityTagEnabled() bool { return r0 } -type mockConstructorTestingTNewConfig interface { +// NewConfig creates a new instance of Config. 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 NewConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { +}) *Config { mock := &Config{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/mocks/eth_client.go b/core/chains/evm/gas/mocks/eth_client.go index 5389661bc56..2b0aaff0257 100644 --- a/core/chains/evm/gas/mocks/eth_client.go +++ b/core/chains/evm/gas/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -42,13 +42,12 @@ func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blo return r0, r1 } -type mockConstructorTestingTNewETHClient interface { +// NewETHClient creates a new instance of ETHClient. 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 NewETHClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewETHClient creates a new instance of ETHClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewETHClient(t mockConstructorTestingTNewETHClient) *ETHClient { +}) *ETHClient { mock := ÐClient{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index 2744d00d805..80ab3c68cc0 100644 --- a/core/chains/evm/gas/mocks/evm_estimator.go +++ b/core/chains/evm/gas/mocks/evm_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -233,13 +233,12 @@ func (_m *EvmEstimator) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewEvmEstimator interface { +// NewEvmEstimator creates a new instance of EvmEstimator. 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 NewEvmEstimator(t interface { mock.TestingT Cleanup(func()) -} - -// NewEvmEstimator creates a new instance of EvmEstimator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewEvmEstimator(t mockConstructorTestingTNewEvmEstimator) *EvmEstimator { +}) *EvmEstimator { mock := &EvmEstimator{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index dbca58dcdd5..42ea96cd50b 100644 --- a/core/chains/evm/gas/mocks/evm_fee_estimator.go +++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -220,13 +220,12 @@ func (_m *EvmFeeEstimator) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewEvmFeeEstimator interface { +// NewEvmFeeEstimator creates a new instance of EvmFeeEstimator. 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 NewEvmFeeEstimator(t interface { mock.TestingT Cleanup(func()) -} - -// NewEvmFeeEstimator creates a new instance of EvmFeeEstimator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewEvmFeeEstimator(t mockConstructorTestingTNewEvmFeeEstimator) *EvmFeeEstimator { +}) *EvmFeeEstimator { mock := &EvmFeeEstimator{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/mocks/rpc_client.go b/core/chains/evm/gas/mocks/rpc_client.go index ee3c48c3320..6f6ac8d6b79 100644 --- a/core/chains/evm/gas/mocks/rpc_client.go +++ b/core/chains/evm/gas/mocks/rpc_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -30,13 +30,12 @@ func (_m *RPCClient) CallContext(ctx context.Context, result interface{}, method return r0 } -type mockConstructorTestingTNewRPCClient interface { +// NewRPCClient creates a new instance of RPCClient. 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 NewRPCClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewRPCClient creates a new instance of RPCClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRPCClient(t mockConstructorTestingTNewRPCClient) *RPCClient { +}) *RPCClient { mock := &RPCClient{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index c6f8edbf04b..bd3106c2ad4 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -8,7 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" - "golang.org/x/exp/maps" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" @@ -21,7 +22,6 @@ import ( evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -30,7 +30,7 @@ import ( // //go:generate mockery --quiet --name EvmFeeEstimator --output ./mocks/ --case=underscore type EvmFeeEstimator interface { - services.ServiceCtx + services.Service commontypes.HeadTrackable[*evmtypes.Head, common.Hash] // L1Oracle returns the L1 gas price oracle only if the chain has one, e.g. OP stack L2s and Arbitrum. @@ -107,7 +107,7 @@ type EvmPriorAttempt struct { //go:generate mockery --quiet --name EvmEstimator --output ./mocks/ --case=underscore type EvmEstimator interface { commontypes.HeadTrackable[*evmtypes.Head, common.Hash] - services.ServiceCtx + services.Service // GetLegacyGas Calculates initial gas fee for non-EIP1559 transaction // maxGasPriceWei parameter is the highest possible gas fee cap that the function will return @@ -214,10 +214,10 @@ func (e *WrappedEvmEstimator) Ready() error { } func (e *WrappedEvmEstimator) HealthReport() map[string]error { - report := map[string]error{e.Name(): e.StartStopOnce.Healthy()} - maps.Copy(report, e.EvmEstimator.HealthReport()) + report := map[string]error{e.Name(): e.Healthy()} + services.CopyHealth(report, e.EvmEstimator.HealthReport()) if e.l1Oracle != nil { - maps.Copy(report, e.l1Oracle.HealthReport()) + services.CopyHealth(report, e.l1Oracle.HealthReport()) } return report diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 13ec5e29dd8..8cf10325d47 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -5,12 +5,12 @@ import ( "errors" "fmt" "math/big" + "slices" "sync" "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "golang.org/x/exp/slices" "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -110,10 +110,8 @@ func (o *l1GasPriceOracle) Close() error { }) } -func (o *l1GasPriceOracle) Ready() error { return o.StartStopOnce.Ready() } - func (o *l1GasPriceOracle) HealthReport() map[string]error { - return map[string]error{o.Name(): o.StartStopOnce.Healthy()} + return map[string]error{o.Name(): o.Healthy()} } func (o *l1GasPriceOracle) run() { diff --git a/core/chains/evm/gas/rollups/mocks/eth_client.go b/core/chains/evm/gas/rollups/mocks/eth_client.go index 5389661bc56..2b0aaff0257 100644 --- a/core/chains/evm/gas/rollups/mocks/eth_client.go +++ b/core/chains/evm/gas/rollups/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -42,13 +42,12 @@ func (_m *ETHClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blo return r0, r1 } -type mockConstructorTestingTNewETHClient interface { +// NewETHClient creates a new instance of ETHClient. 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 NewETHClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewETHClient creates a new instance of ETHClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewETHClient(t mockConstructorTestingTNewETHClient) *ETHClient { +}) *ETHClient { mock := ÐClient{} mock.Mock.Test(t) diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index e148c0e9ac4..31407300b64 100644 --- a/core/chains/evm/gas/rollups/mocks/l1_oracle.go +++ b/core/chains/evm/gas/rollups/mocks/l1_oracle.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -113,13 +113,12 @@ func (_m *L1Oracle) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewL1Oracle interface { +// NewL1Oracle creates a new instance of L1Oracle. 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 NewL1Oracle(t interface { mock.TestingT Cleanup(func()) -} - -// NewL1Oracle creates a new instance of L1Oracle. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewL1Oracle(t mockConstructorTestingTNewL1Oracle) *L1Oracle { +}) *L1Oracle { mock := &L1Oracle{} mock.Mock.Test(t) diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 330142b9dc0..d30571f331d 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -4,26 +4,23 @@ import ( "context" "errors" "math/big" + "slices" "sync" "testing" "time" - "golang.org/x/exp/maps" - "golang.org/x/exp/slices" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/ethereum/go-ethereum" gethCommon "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/onsi/gomega" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" + + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -31,9 +28,13 @@ import ( httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -402,7 +403,7 @@ func TestHeadTracker_Start_LoadsLatestChain(t *testing.T) { gomega.NewWithT(t).Eventually(func() bool { report := ht.headTracker.HealthReport() - maps.Copy(report, ht.headBroadcaster.HealthReport()) + services.CopyHealth(report, ht.headBroadcaster.HealthReport()) return !slices.ContainsFunc(maps.Values(report), func(e error) bool { return e != nil }) }, 5*time.Second, testutils.TestInterval).Should(gomega.Equal(true)) diff --git a/core/chains/evm/headtracker/mocks/config.go b/core/chains/evm/headtracker/mocks/config.go index 45d335a7c49..b505cfc445d 100644 --- a/core/chains/evm/headtracker/mocks/config.go +++ b/core/chains/evm/headtracker/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -41,13 +41,12 @@ func (_m *Config) FinalityDepth() uint32 { return r0 } -type mockConstructorTestingTNewConfig interface { +// NewConfig creates a new instance of Config. 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 NewConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { +}) *Config { mock := &Config{} mock.Mock.Test(t) diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index c7342de01e6..bc9ba1cf6cf 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -188,7 +188,7 @@ func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr log func (b *broadcaster) Start(context.Context) error { return b.StartOnce("LogBroadcaster", func() error { - b.wgDone.Add(2) + b.wgDone.Add(1) go b.awaitInitialSubscribers() b.mailMon.Monitor(b.changeSubscriberStatus, "LogBroadcaster", "ChangeSubscriber", b.evmChainID.String()) return nil @@ -220,7 +220,7 @@ func (b *broadcaster) Name() string { } func (b *broadcaster) HealthReport() map[string]error { - return map[string]error{b.Name(): b.StartStopOnce.Healthy()} + return map[string]error{b.Name(): b.Healthy()} } func (b *broadcaster) awaitInitialSubscribers() { @@ -234,11 +234,11 @@ func (b *broadcaster) awaitInitialSubscribers() { case <-b.DependentAwaiter.AwaitDependents(): // ensure that any queued dependent subscriptions are registered first b.onChangeSubscriberStatus() + b.wgDone.Add(1) go b.startResubscribeLoop() return case <-b.chStop: - b.wgDone.Done() // because startResubscribeLoop won't be called return } } diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index d55a44373f2..58e81132b0f 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -58,20 +58,10 @@ type broadcasterHelper struct { pipelineHelper cltest.JobPipelineV2TestHelper } -func newBroadcasterHelper(t *testing.T, blockHeight int64, timesSubscribe int, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - return broadcasterHelperCfg{}.new(t, blockHeight, timesSubscribe, nil, overridesFn) -} - -type broadcasterHelperCfg struct { - highestSeenHead *evmtypes.Head - db *sqlx.DB -} +func newBroadcasterHelper(t *testing.T, blockHeight int64, timesSubscribe int, filterLogsResult []types.Log, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { + // ensure we check before registering any mock Cleanup assertions + testutils.SkipShortDB(t) -func (c broadcasterHelperCfg) new(t *testing.T, blockHeight int64, timesSubscribe int, filterLogsResult []types.Log, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - if c.db == nil { - // ensure we check before registering any mock Cleanup assertions - testutils.SkipShortDB(t) - } expectedCalls := mockEthClientExpectedCalls{ SubscribeFilterLogs: timesSubscribe, HeaderByNumber: 1, @@ -81,21 +71,13 @@ func (c broadcasterHelperCfg) new(t *testing.T, blockHeight int64, timesSubscrib chchRawLogs := make(chan evmtest.RawSub[types.Log], timesSubscribe) mockEth := newMockEthClient(t, chchRawLogs, blockHeight, expectedCalls) - helper := c.newWithEthClient(t, mockEth.EthClient, overridesFn) + helper := newBroadcasterHelperWithEthClient(t, mockEth.EthClient, nil, overridesFn) helper.chchRawLogs = chchRawLogs helper.mockEth = mockEth return helper } func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, highestSeenHead *evmtypes.Head, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - return broadcasterHelperCfg{highestSeenHead: highestSeenHead}.newWithEthClient(t, ethClient, overridesFn) -} - -func (c broadcasterHelperCfg) newWithEthClient(t *testing.T, ethClient evmclient.Client, overridesFn func(*chainlink.Config, *chainlink.Secrets)) *broadcasterHelper { - if c.db == nil { - c.db = pgtest.NewSqlxDB(t) - } - globalConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.LogQueries = ptr(true) finality := uint32(10) @@ -109,25 +91,26 @@ func (c broadcasterHelperCfg) newWithEthClient(t *testing.T, ethClient evmclient lggr := logger.TestLogger(t) mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) - orm := log.NewORM(c.db, lggr, config.Database(), cltest.FixtureChainID) - lb := log.NewTestBroadcaster(orm, ethClient, config.EVM(), lggr, c.highestSeenHead, mailMon) - kst := cltest.NewKeyStore(t, c.db, globalConfig.Database()) + db := pgtest.NewSqlxDB(t) + orm := log.NewORM(db, lggr, config.Database(), cltest.FixtureChainID) + lb := log.NewTestBroadcaster(orm, ethClient, config.EVM(), lggr, highestSeenHead, mailMon) + kst := cltest.NewKeyStore(t, db, globalConfig.Database()) cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{ Client: ethClient, GeneralConfig: globalConfig, - DB: c.db, + DB: db, KeyStore: kst.Eth(), LogBroadcaster: &log.NullBroadcaster{}, MailMon: mailMon, }) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - pipelineHelper := cltest.NewJobPipelineV2(t, config.WebServer(), config.JobPipeline(), config.Database(), legacyChains, c.db, kst, nil, nil) + pipelineHelper := cltest.NewJobPipelineV2(t, config.WebServer(), config.JobPipeline(), config.Database(), legacyChains, db, kst, nil, nil) return &broadcasterHelper{ t: t, lb: lb, - db: c.db, + db: db, globalConfig: globalConfig, config: config, pipelineHelper: pipelineHelper, @@ -194,10 +177,10 @@ func (helper *broadcasterHelper) stop() { assert.NoError(helper.t, err) } -func newMockContract() *logmocks.AbigenContract { +func newMockContract(t *testing.T) *logmocks.AbigenContract { addr := testutils.NewAddress() - contract := new(logmocks.AbigenContract) - contract.On("Address").Return(addr) + contract := logmocks.NewAbigenContract(t) + contract.On("Address").Return(addr).Maybe() return contract } @@ -329,15 +312,10 @@ func (listener *simpleLogListener) getUniqueLogsBlockNumbers() []uint64 { func (listener *simpleLogListener) requireAllReceived(t *testing.T, expectedState *received) { received := listener.received + defer func() { assert.EqualValues(t, expectedState.getUniqueLogs(), received.getUniqueLogs()) }() require.Eventually(t, func() bool { return len(received.getUniqueLogs()) == len(expectedState.getUniqueLogs()) }, testutils.WaitTimeout(t), time.Second, "len(received.uniqueLogs): %v is not equal len(expectedState.uniqueLogs): %v", len(received.getUniqueLogs()), len(expectedState.getUniqueLogs())) - - received.Lock() - defer received.Unlock() - for i, ul := range expectedState.getUniqueLogs() { - assert.Equal(t, ul, received.uniqueLogs[i]) - } } func (listener *simpleLogListener) handleLogBroadcast(lb log.Broadcast) bool { diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index ed4337a8b39..137b4c7292a 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -3,6 +3,7 @@ package log_test import ( "context" "math/big" + "slices" "sync/atomic" "testing" "time" @@ -16,16 +17,14 @@ import ( "github.com/stretchr/testify/require" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" @@ -36,11 +35,11 @@ func TestBroadcaster_AwaitsInitialSubscribersOnStartup(t *testing.T) { g := gomega.NewWithT(t) const blockHeight int64 = 123 - helper := newBroadcasterHelper(t, blockHeight, 1, nil) + helper := newBroadcasterHelper(t, blockHeight, 1, nil, nil) helper.lb.AddDependents(2) var listener = helper.newLogListenerWithJob("A") - helper.register(listener, newMockContract(), 1) + helper.register(listener, newMockContract(t), 1) helper.start() defer helper.stop() @@ -98,11 +97,11 @@ func TestBroadcaster_ResubscribesOnAddOrRemoveContract(t *testing.T) { listener := helper.newLogListenerWithJob("initial") - helper.register(listener, newMockContract(), numConfirmations) + helper.register(listener, newMockContract(t), numConfirmations) for i := 0; i < numContracts; i++ { listener := helper.newLogListenerWithJob("") - helper.register(listener, newMockContract(), 1) + helper.register(listener, newMockContract(t), 1) } helper.start() @@ -122,7 +121,7 @@ func TestBroadcaster_ResubscribesOnAddOrRemoveContract(t *testing.T) { } listenerLast := helper.newLogListenerWithJob("last") - helper.register(listenerLast, newMockContract(), 1) + helper.register(listenerLast, newMockContract(t), 1) require.Eventually(t, func() bool { return helper.mockEth.UnsubscribeCallCount() >= 1 }, testutils.WaitTimeout(t), time.Second) gomega.NewWithT(t).Consistently(func() int32 { return helper.mockEth.SubscribeCallCount() }, 1*time.Second, cltest.DBPollingInterval).Should(gomega.Equal(int32(2))) @@ -156,10 +155,10 @@ func TestBroadcaster_BackfillOnNodeStartAndOnReplay(t *testing.T) { var backfillCount atomic.Int64 listener := helper.newLogListenerWithJob("one") - helper.register(listener, newMockContract(), uint32(maxNumConfirmations)) + helper.register(listener, newMockContract(t), uint32(maxNumConfirmations)) listener2 := helper.newLogListenerWithJob("two") - helper.register(listener2, newMockContract(), uint32(2)) + helper.register(listener2, newMockContract(t), uint32(2)) blockBackfillDepth := helper.config.EVM().BlockBackfillDepth() @@ -224,35 +223,20 @@ func TestBroadcaster_ReplaysLogs(t *testing.T) { // Replay from block 2, the logs should be delivered. An incoming head must be simulated to // trigger log delivery. helper.lb.ReplayFromBlock(2, false) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 10, - EndBlock: 10, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(10, 11), helper.lb) require.Eventually(t, func() bool { return len(listener.getUniqueLogs()) == 2 }, testutils.WaitTimeout(t), time.Second, "expected unique logs to be 2 but was %d", len(listener.getUniqueLogs())) - // Replay again, the logs are already marked consumed so they should not be included in + // Replay again, the logs are already marked consumed, so they should not be included in // getUniqueLogs. helper.lb.ReplayFromBlock(2, false) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 11, - EndBlock: 11, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(11, 12), helper.lb) require.Eventually(t, func() bool { return len(listener.getUniqueLogs()) == 2 }, testutils.WaitTimeout(t), time.Second, "expected unique logs to be 2 but was %d", len(listener.getUniqueLogs())) // Replay again with forceBroadcast. The logs are consumed again. helper.lb.ReplayFromBlock(2, true) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 12, - EndBlock: 12, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(12, 13), helper.lb) require.Eventually(t, func() bool { return len(listener.getUniqueLogs()) == 4 }, testutils.WaitTimeout(t), time.Second, "expected unique logs to be 4 but was %d", len(listener.getUniqueLogs())) @@ -262,15 +246,8 @@ func TestBroadcaster_ReplaysLogs(t *testing.T) { } func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { - db := pgtest.NewSqlxDB(t) - lggr := logger.TestLogger(t) - cfg := configtest.NewGeneralConfig(t, nil) - - orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) - - helperCfg := broadcasterHelperCfg{db: db} - contract1 := newMockContract() - contract2 := newMockContract() + contract1 := newMockContract(t) + contract2 := newMockContract(t) blocks := cltest.NewBlocks(t, 10) const ( @@ -285,171 +262,134 @@ func TestBroadcaster_BackfillUnconsumedAfterCrash(t *testing.T) { contract1.On("ParseLog", log1).Return(flux_aggregator_wrapper.FluxAggregatorNewRound{}, nil) contract2.On("ParseLog", log2).Return(flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, nil) - - // Pool two logs from subscription, then shut down - helper := helperCfg.new(t, 0, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].FinalityDepth = ptr[uint32](confs) + t.Run("pool two logs from subscription, then shut down", func(t *testing.T) { + helper := newBroadcasterHelper(t, 0, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].FinalityDepth = ptr[uint32](confs) + }) + lggr := logger.TestLogger(t) + orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + + listener := helper.newLogListenerWithJob("one") + listener.SkipMarkingConsumed(true) + listener2 := helper.newLogListenerWithJob("two") + listener2.SkipMarkingConsumed(true) + expBlock := int64(log1.BlockNumber) + helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(0, 2), orm, &expBlock, func() { + chRawLogs := <-helper.chchRawLogs + chRawLogs.TrySend(log1) + chRawLogs.TrySend(log2) + }) + // Pool min block in DB and neither listener received a broadcast + blockNum, err := orm.GetPendingMinBlock() + require.NoError(t, err) + require.NotNil(t, blockNum) + require.Equal(t, int64(log1.BlockNumber), *blockNum) + require.Empty(t, listener.getUniqueLogs()) + require.Empty(t, listener2.getUniqueLogs()) + helper.requireBroadcastCount(0) }) - listener := helper.newLogListenerWithJob("one") - listener.SkipMarkingConsumed(true) - listener2 := helper.newLogListenerWithJob("two") - listener2.SkipMarkingConsumed(true) - func() { - helper.lb.AddDependents(2) - helper.start() - defer helper.stop() - helper.register(listener, contract1, confs) - helper.register(listener2, contract2, confs) - helper.lb.DependentReady() - helper.lb.DependentReady() - - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 1, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, + t.Run("backfill pool with both, then broadcast one, but don't consume", func(t *testing.T) { + helper := newBroadcasterHelper(t, 2, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - - chRawLogs := <-helper.chchRawLogs - chRawLogs.TrySend(log1) - chRawLogs.TrySend(log2) - - <-headsDone - - require.Eventually(t, func() bool { - blockNum, err := orm.GetPendingMinBlock() - return assert.NoError(t, err) && blockNum != nil && *blockNum == int64(log1.BlockNumber) - }, testutils.WaitTimeout(t), time.Second) - }() - - // Pool min block in DB and neither listener received a broadcast - blockNum, err := orm.GetPendingMinBlock() - require.NoError(t, err) - require.NotNil(t, blockNum) - require.Equal(t, int64(log1.BlockNumber), *blockNum) - require.Empty(t, listener.getUniqueLogs()) - require.Empty(t, listener2.getUniqueLogs()) - helper.requireBroadcastCount(0) - - // Backfill pool with both, then broadcast one, but don't consume - helper = helperCfg.new(t, 2, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].FinalityDepth = ptr[uint32](confs) + lggr := logger.TestLogger(t) + orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + + listener := helper.newLogListenerWithJob("one") + listener.SkipMarkingConsumed(true) + listener2 := helper.newLogListenerWithJob("two") + listener2.SkipMarkingConsumed(true) + expBlock := int64(log2.BlockNumber) + helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(2, 5), orm, &expBlock, nil) + + // Pool min block in DB and one listener received but didn't consume + blockNum, err := orm.GetPendingMinBlock() + require.NoError(t, err) + require.NotNil(t, blockNum) + require.Equal(t, int64(log2.BlockNumber), *blockNum) + require.NotEmpty(t, listener.getUniqueLogs()) + require.Empty(t, listener2.getUniqueLogs()) + c, err := orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) + require.NoError(t, err) + require.False(t, c) }) - listener = helper.newLogListenerWithJob("one") - listener.SkipMarkingConsumed(true) - listener2 = helper.newLogListenerWithJob("two") - listener2.SkipMarkingConsumed(true) - func() { - helper.lb.AddDependents(2) - helper.start() - defer helper.stop() - helper.register(listener, contract1, confs) - helper.register(listener2, contract2, confs) - helper.lb.DependentReady() - helper.lb.DependentReady() - - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 2, - EndBlock: 4, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, + t.Run("backfill pool and broadcast two, but only consume one", func(t *testing.T) { + helper := newBroadcasterHelper(t, 4, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].FinalityDepth = ptr[uint32](confs) }) - - require.Eventually(t, func() bool { - blockNum, err := orm.GetPendingMinBlock() - return assert.NoError(t, err) && blockNum != nil && *blockNum == int64(log2.BlockNumber) - }, testutils.WaitTimeout(t), time.Second) - }() - - // Pool min block in DB and one listener received but didn't consume - blockNum, err = orm.GetPendingMinBlock() - require.NoError(t, err) - require.NotNil(t, blockNum) - require.Equal(t, int64(log2.BlockNumber), *blockNum) - require.NotEmpty(t, listener.getUniqueLogs()) - require.Empty(t, listener2.getUniqueLogs()) - c, err := orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) - require.NoError(t, err) - require.False(t, c) - - // Backfill pool and broadcast two, but only consume one - helper = helperCfg.new(t, 4, 1, logs, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].FinalityDepth = ptr[uint32](confs) + lggr := logger.TestLogger(t) + orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + + listener := helper.newLogListenerWithJob("one") + listener2 := helper.newLogListenerWithJob("two") + listener2.SkipMarkingConsumed(true) + helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(5, 8), orm, nil, nil) + + // Pool empty and one consumed but other didn't + blockNum, err := orm.GetPendingMinBlock() + require.NoError(t, err) + require.Nil(t, blockNum) + require.NotEmpty(t, listener.getUniqueLogs()) + require.NotEmpty(t, listener2.getUniqueLogs()) + c, err := orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) + require.NoError(t, err) + require.True(t, c) + c, err = orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) + require.NoError(t, err) + require.False(t, c) }) - listener = helper.newLogListenerWithJob("one") - listener2 = helper.newLogListenerWithJob("two") - listener2.SkipMarkingConsumed(true) - func() { - helper.lb.AddDependents(2) - helper.start() - defer helper.stop() - helper.register(listener, contract1, confs) - helper.register(listener2, contract2, confs) - helper.lb.DependentReady() - helper.lb.DependentReady() - - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 5, - EndBlock: 7, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, + t.Run("backfill pool, broadcast and consume one", func(t *testing.T) { + helper := newBroadcasterHelper(t, 7, 1, logs[1:], func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].FinalityDepth = ptr[uint32](confs) }) + lggr := logger.TestLogger(t) + orm := log.NewORM(helper.db, lggr, helper.config.Database(), cltest.FixtureChainID) + listener := helper.newLogListenerWithJob("one") + listener2 := helper.newLogListenerWithJob("two") + helper.simulateHeads(t, listener, listener2, contract1, contract2, confs, blocks.Slice(8, 9), orm, nil, nil) + + // Pool empty, one broadcasted and consumed + blockNum, err := orm.GetPendingMinBlock() + require.NoError(t, err) + require.Nil(t, blockNum) + require.Empty(t, listener.getUniqueLogs()) + require.NotEmpty(t, listener2.getUniqueLogs()) + c, err := orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) + require.NoError(t, err) + require.True(t, c) + }) +} - require.Eventually(t, func() bool { - blockNum, err := orm.GetPendingMinBlock() - return assert.NoError(t, err) && blockNum == nil - }, testutils.WaitTimeout(t), time.Second) - }() +func (helper *broadcasterHelper) simulateHeads(t *testing.T, listener, listener2 *simpleLogListener, + contract1, contract2 *logmocks.AbigenContract, confs uint32, heads []*evmtypes.Head, orm log.ORM, assertBlock *int64, do func()) { + helper.lb.AddDependents(2) + helper.start() + defer helper.stop() + helper.register(listener, contract1, confs) + helper.register(listener2, contract2, confs) + helper.lb.DependentReady() + helper.lb.DependentReady() - // Pool empty and one consumed but other didn't - blockNum, err = orm.GetPendingMinBlock() - require.NoError(t, err) - require.Nil(t, blockNum) - require.NotEmpty(t, listener.getUniqueLogs()) - require.NotEmpty(t, listener2.getUniqueLogs()) - c, err = orm.WasBroadcastConsumed(log1.BlockHash, log1.Index, listener.JobID()) - require.NoError(t, err) - require.True(t, c) - c, err = orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) - require.NoError(t, err) - require.False(t, c) + headsDone := cltest.SimulateIncomingHeads(t, heads, helper.lb) - // Backfill pool, broadcast and consume one - helper = helperCfg.new(t, 7, 1, logs[1:], func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].FinalityDepth = ptr[uint32](confs) - }) - listener = helper.newLogListenerWithJob("one") - listener2 = helper.newLogListenerWithJob("two") - func() { - helper.lb.AddDependents(2) - helper.start() - defer helper.stop() - helper.register(listener, contract1, confs) - helper.register(listener2, contract2, confs) - helper.lb.DependentReady() - helper.lb.DependentReady() - - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 8, - EndBlock: 8, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - }) + if do != nil { + do() + } - require.Eventually(t, func() bool { - blockNum, err := orm.GetPendingMinBlock() - return assert.NoError(t, err) && blockNum == nil - }, testutils.WaitTimeout(t), time.Second) - }() - // Pool empty, one broadcasted and consumed - blockNum, err = orm.GetPendingMinBlock() - require.NoError(t, err) - require.Nil(t, blockNum) - require.Empty(t, listener.getUniqueLogs()) - require.NotEmpty(t, listener2.getUniqueLogs()) - c, err = orm.WasBroadcastConsumed(log2.BlockHash, log2.Index, listener2.JobID()) - require.NoError(t, err) - require.True(t, c) + <-headsDone + + require.Eventually(t, func() bool { + blockNum, err := orm.GetPendingMinBlock() + if !assert.NoError(t, err) { + return false + } + if assertBlock == nil { + return blockNum == nil + } else if blockNum == nil { + return false + } + return *assertBlock == *blockNum + }, testutils.WaitTimeout(t), time.Second) } func TestBroadcaster_ShallowBackfillOnNodeStart(t *testing.T) { @@ -478,10 +418,10 @@ func TestBroadcaster_ShallowBackfillOnNodeStart(t *testing.T) { var backfillCount atomic.Int64 listener := helper.newLogListenerWithJob("one") - helper.register(listener, newMockContract(), uint32(10)) + helper.register(listener, newMockContract(t), uint32(10)) listener2 := helper.newLogListenerWithJob("two") - helper.register(listener2, newMockContract(), uint32(2)) + helper.register(listener2, newMockContract(t), uint32(2)) // the backfill does not use the height from DB because BlockBackfillSkip is true mockEth.CheckFilterLogs = func(fromBlock int64, toBlock int64) { @@ -546,7 +486,7 @@ func TestBroadcaster_BackfillInBatches(t *testing.T) { } listener := helper.newLogListenerWithJob("initial") - helper.register(listener, newMockContract(), numConfirmations) + helper.register(listener, newMockContract(t), numConfirmations) helper.start() defer helper.stop() @@ -606,7 +546,7 @@ func TestBroadcaster_BackfillALargeNumberOfLogs(t *testing.T) { } listener := helper.newLogListenerWithJob("initial") - helper.register(listener, newMockContract(), 1) + helper.register(listener, newMockContract(t), 1) helper.start() defer helper.stop() g.Eventually(func() int64 { return backfillCount.Load() }, testutils.WaitTimeout(t), time.Second).Should(gomega.Equal(int64(expectedBatches))) @@ -617,7 +557,7 @@ func TestBroadcaster_BackfillALargeNumberOfLogs(t *testing.T) { func TestBroadcaster_BroadcastsToCorrectRecipients(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, nil) + helper := newBroadcasterHelper(t, blockHeight, 1, nil, nil) contract1, err := flux_aggregator_wrapper.NewFluxAggregator(testutils.NewAddress(), nil) require.NoError(t, err) @@ -650,12 +590,7 @@ func TestBroadcaster_BroadcastsToCorrectRecipients(t *testing.T) { helper.start() defer helper.stop() - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 9, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(0, 10), helper.lb) defer helper.unsubscribeAll() @@ -681,7 +616,7 @@ func TestBroadcaster_BroadcastsToCorrectRecipients(t *testing.T) { func TestBroadcaster_BroadcastsAtCorrectHeights(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, nil) + helper := newBroadcasterHelper(t, blockHeight, 1, nil, nil) helper.start() contract1, err := flux_aggregator_wrapper.NewFluxAggregator(testutils.NewAddress(), nil) @@ -700,12 +635,7 @@ func TestBroadcaster_BroadcastsAtCorrectHeights(t *testing.T) { helper.register(listener1, contract1, 1) helper.register(listener2, contract1, 8) - _ = cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 9, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + _ = cltest.SimulateIncomingHeads(t, blocks.Slice(0, 10), helper.lb) chRawLogs := <-helper.chchRawLogs @@ -762,7 +692,7 @@ func TestBroadcaster_BroadcastsAtCorrectHeights(t *testing.T) { func TestBroadcaster_DeletesOldLogsAfterNumberOfHeads(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, blockHeight, 1, nil, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](1) }) helper.start() @@ -786,12 +716,7 @@ func TestBroadcaster_DeletesOldLogsAfterNumberOfHeads(t *testing.T) { helper.register(listener1, contract1, 1) helper.register(listener2, contract1, 3) - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 5, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(0, 6), helper.lb) chRawLogs := <-helper.chchRawLogs @@ -803,24 +728,14 @@ func TestBroadcaster_DeletesOldLogsAfterNumberOfHeads(t *testing.T) { <-headsDone helper.register(listener3, contract1, 1) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 6, - EndBlock: 8, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(6, 9), helper.lb) // the new listener should still receive 2 of the 3 logs helper.requireBroadcastCount(8) require.Equal(t, 2, len(listener3.received.getUniqueLogs())) helper.register(listener4, contract1, 1) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 9, - EndBlock: 11, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(9, 12), helper.lb) // but this one should receive none require.Equal(t, 0, len(listener4.received.getUniqueLogs())) @@ -828,7 +743,7 @@ func TestBroadcaster_DeletesOldLogsAfterNumberOfHeads(t *testing.T) { func TestBroadcaster_DeletesOldLogsOnlyAfterFinalityDepth(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, blockHeight, 1, nil, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](4) }) helper.start() @@ -852,12 +767,7 @@ func TestBroadcaster_DeletesOldLogsOnlyAfterFinalityDepth(t *testing.T) { helper.register(listener1, contract1, 1) helper.register(listener2, contract1, 3) - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 5, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(0, 6), helper.lb) chRawLogs := <-helper.chchRawLogs @@ -869,24 +779,14 @@ func TestBroadcaster_DeletesOldLogsOnlyAfterFinalityDepth(t *testing.T) { helper.requireBroadcastCount(6) helper.register(listener3, contract1, 1) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 7, - EndBlock: 8, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(7, 9), helper.lb) // the new listener should still receive 3 logs because of finality depth being higher than max NumConfirmations helper.requireBroadcastCount(9) require.Equal(t, 3, len(listener3.received.getUniqueLogs())) helper.register(listener4, contract1, 1) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 10, - EndBlock: 11, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(10, 12), helper.lb) // but this one should receive none require.Equal(t, 0, len(listener4.received.getUniqueLogs())) @@ -894,7 +794,7 @@ func TestBroadcaster_DeletesOldLogsOnlyAfterFinalityDepth(t *testing.T) { func TestBroadcaster_FilterByTopicValues(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, blockHeight, 1, nil, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](3) }) helper.start() @@ -955,12 +855,7 @@ func TestBroadcaster_FilterByTopicValues(t *testing.T) { }, ) - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 5, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(0, 6), helper.lb) chRawLogs := <-helper.chchRawLogs @@ -979,7 +874,7 @@ func TestBroadcaster_FilterByTopicValues(t *testing.T) { func TestBroadcaster_BroadcastsWithOneDelayedLog(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, blockHeight, 1, nil, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](2) }) helper.start() @@ -1006,21 +901,11 @@ func TestBroadcaster_BroadcastsWithOneDelayedLog(t *testing.T) { chRawLogs.TrySend(addr1SentLogs[1]) chRawLogs.TrySend(addr1SentLogs[2]) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 3, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(0, 4), helper.lb) chRawLogs.TrySend(addr1SentLogs[3]) - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 4, - EndBlock: 8, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(4, 9), helper.lb) helper.requireBroadcastCount(4) helper.stop() @@ -1028,7 +913,7 @@ func TestBroadcaster_BroadcastsWithOneDelayedLog(t *testing.T) { func TestBroadcaster_BroadcastsAtCorrectHeightsWithLogsEarlierThanHeads(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, nil) + helper := newBroadcasterHelper(t, blockHeight, 1, nil, nil) helper.start() contract1, err := flux_aggregator_wrapper.NewFluxAggregator(testutils.NewAddress(), nil) @@ -1050,12 +935,7 @@ func TestBroadcaster_BroadcastsAtCorrectHeightsWithLogsEarlierThanHeads(t *testi chRawLogs.TrySend(log) } - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 9, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(0, 10), helper.lb) helper.requireBroadcastCount(3) helper.stop() @@ -1074,7 +954,7 @@ func TestBroadcaster_BroadcastsAtCorrectHeightsWithLogsEarlierThanHeads(t *testi func TestBroadcaster_BroadcastsAtCorrectHeightsWithHeadsEarlierThanLogs(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, blockHeight, 1, nil, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FinalityDepth = ptr[uint32](2) }) helper.start() @@ -1094,23 +974,13 @@ func TestBroadcaster_BroadcastsAtCorrectHeightsWithHeadsEarlierThanLogs(t *testi chRawLogs := <-helper.chchRawLogs - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 0, - EndBlock: 6, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(0, 7), helper.lb) for _, log := range addr1SentLogs { chRawLogs.TrySend(log) } - <-cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 7, - EndBlock: 8, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + <-cltest.SimulateIncomingHeads(t, blocks.Slice(7, 9), helper.lb) helper.requireBroadcastCount(3) helper.stop() @@ -1136,9 +1006,9 @@ func TestBroadcaster_Register_ResubscribesToMostRecentlySeenBlock(t *testing.T) ) var ( ethClient = evmclimocks.NewClient(t) - contract0 = newMockContract() - contract1 = newMockContract() - contract2 = newMockContract() + contract0 = newMockContract(t) + contract1 = newMockContract(t) + contract2 = newMockContract(t) ) mockEth := &evmtest.MockEth{EthClient: ethClient} chchRawLogs := make(chan evmtest.RawSub[types.Log], backfillTimes) @@ -1279,8 +1149,8 @@ func TestBroadcaster_ReceivesAllLogsWhenResubscribing(t *testing.T) { tests := []struct { name string - blockHeight1 int64 - blockHeight2 int64 + blockHeight1 int + blockHeight2 int batch1 []uint backfillableLogs []uint batch2 []uint @@ -1341,20 +1211,11 @@ func TestBroadcaster_ReceivesAllLogsWhenResubscribing(t *testing.T) { }, } - batchContains := func(batch []uint, n uint) bool { - for _, x := range batch { - if x == n { - return true - } - } - return false - } - for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { const backfillDepth = 5 - helper := newBroadcasterHelper(t, test.blockHeight1, 2, func(c *chainlink.Config, s *chainlink.Secrets) { + helper := newBroadcasterHelper(t, int64(test.blockHeight1), 2, nil, func(c *chainlink.Config, s *chainlink.Secrets) { // something other than default c.EVM[0].BlockBackfillDepth = ptr[uint32](backfillDepth) }) @@ -1373,33 +1234,22 @@ func TestBroadcaster_ReceivesAllLogsWhenResubscribing(t *testing.T) { // Register listener A helper.register(logListenerA, contractA, 1) - lggr := logger.TestLogger(t) // Send initial logs chRawLogs1 := <-helper.chchRawLogs - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: test.blockHeight1, - EndBlock: test.blockHeight2 + 1, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable), cltest.HeadTrackableFunc(func(_ context.Context, head *evmtypes.Head) { - lggr.Infof("------------ HEAD TRACKABLE (%v) --------------", head.Number) - if _, exists := logsA[uint(head.Number)]; !exists { - lggr.Warnf(" ** not exists") - return - } else if !batchContains(test.batch1, uint(head.Number)) { - lggr.Warnf(" ** not batchContains %v %v", head.Number, test.batch1) - return + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(test.blockHeight1, test.blockHeight2+2), + helper.lb, cltest.HeadTrackableFunc(func(_ context.Context, head *evmtypes.Head) { + n := uint(head.Number) + if l, ok := logsA[n]; ok && slices.Contains(test.batch1, n) { + chRawLogs1.TrySend(l) } - lggr.Warnf(" ** yup!") - chRawLogs1.TrySend(logsA[uint(head.Number)]) - })}, - }) + })) helper.requireBroadcastCount(len(test.batch1)) expectedA := newReceived(pickLogs(logsA, test.batch1)) logListenerA.requireAllReceived(t, expectedA) <-headsDone - helper.mockEth.EthClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&evmtypes.Head{Number: test.blockHeight2}, nil).Once() + helper.mockEth.EthClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&evmtypes.Head{Number: int64(test.blockHeight2)}, nil).Once() combinedLogs := append(pickLogs(logsA, test.backfillableLogs), pickLogs(logsB, test.backfillableLogs)...) call := helper.mockEth.EthClient.On("FilterLogs", mock.Anything, mock.Anything).Return(combinedLogs, nil).Once() @@ -1409,10 +1259,10 @@ func TestBroadcaster_ReceivesAllLogsWhenResubscribing(t *testing.T) { expected := big.NewInt(0) blockNumber := helper.lb.BackfillBlockNumber() - if blockNumber.Valid && blockNumber.Int64 > test.blockHeight2-backfillDepth { + if blockNumber.Valid && blockNumber.Int64 > int64(test.blockHeight2-backfillDepth) { expected = big.NewInt(blockNumber.Int64) } else if test.blockHeight2 > backfillDepth { - expected = big.NewInt(test.blockHeight2 - backfillDepth) + expected = big.NewInt(int64(test.blockHeight2) - backfillDepth) } require.Equal(t, expected, fromBlock) }) @@ -1422,18 +1272,17 @@ func TestBroadcaster_ReceivesAllLogsWhenResubscribing(t *testing.T) { // Send second batch of new logs chRawLogs2 := <-helper.chchRawLogs - headsDone = cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: test.blockHeight2, - Blocks: blocks, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable), cltest.HeadTrackableFunc(func(_ context.Context, head *evmtypes.Head) { - if _, exists := logsA[uint(head.Number)]; exists && batchContains(test.batch2, uint(head.Number)) { - chRawLogs2.TrySend(logsA[uint(head.Number)]) + headsDone = cltest.SimulateIncomingHeads(t, blocks.Slice(test.blockHeight2, -1), + helper.lb, cltest.HeadTrackableFunc(func(_ context.Context, head *evmtypes.Head) { + n := uint(head.Number) + if l, ok := logsA[n]; ok && slices.Contains(test.batch2, n) { + chRawLogs2.TrySend(l) } - if _, exists := logsB[uint(head.Number)]; exists && batchContains(test.batch2, uint(head.Number)) { - chRawLogs2.TrySend(logsB[uint(head.Number)]) + if l, ok := logsB[n]; ok && slices.Contains(test.batch2, n) { + chRawLogs2.TrySend(l) } - })}, - }) + })) + defer func() { <-headsDone }() expectedA = newReceived(pickLogs(logsA, test.expectedFilteredA)) @@ -1511,7 +1360,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { func TestBroadcaster_InjectsBroadcastRecordFunctions(t *testing.T) { const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 1, nil) + helper := newBroadcasterHelper(t, blockHeight, 1, nil, nil) helper.start() defer helper.stop() @@ -1519,19 +1368,14 @@ func TestBroadcaster_InjectsBroadcastRecordFunctions(t *testing.T) { logListener := helper.newLogListenerWithJob("logListener") - contract := newMockContract() + contract := newMockContract(t) log1, log2 := blocks.LogOnBlockNum(0, contract.Address()), blocks.LogOnBlockNum(1, contract.Address()) contract.On("ParseLog", log1).Return(flux_aggregator_wrapper.FluxAggregatorNewRound{}, nil) contract.On("ParseLog", log2).Return(flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}, nil) helper.register(logListener, contract, uint32(5)) - headsDone := cltest.SimulateIncomingHeads(t, cltest.SimulateIncomingHeadsArgs{ - StartBlock: 3, - EndBlock: 20, - HeadTrackables: []httypes.HeadTrackable{(helper.lb).(httypes.HeadTrackable)}, - Blocks: blocks, - }) + headsDone := cltest.SimulateIncomingHeads(t, blocks.Slice(3, 20), helper.lb) chRawLogs := <-helper.chchRawLogs @@ -1547,7 +1391,7 @@ func TestBroadcaster_ProcessesLogsFromReorgsAndMissedHead(t *testing.T) { g := gomega.NewWithT(t) const startBlockHeight int64 = 0 - helper := newBroadcasterHelper(t, startBlockHeight, 1, nil) + helper := newBroadcasterHelper(t, startBlockHeight, 1, nil, nil) helper.start() defer helper.stop() @@ -1608,7 +1452,7 @@ func TestBroadcaster_ProcessesLogsFromReorgsAndMissedHead(t *testing.T) { for _, event := range events { switch x := event.(type) { case *evmtypes.Head: - (helper.lb).(httypes.HeadTrackable).OnNewLongestChain(ctx, x) + helper.lb.OnNewLongestChain(ctx, x) case types.Log: chRawLogs.TrySend(x) } @@ -1630,7 +1474,7 @@ func TestBroadcaster_BackfillsForNewListeners(t *testing.T) { g := gomega.NewWithT(t) const blockHeight int64 = 0 - helper := newBroadcasterHelper(t, blockHeight, 2, nil) + helper := newBroadcasterHelper(t, blockHeight, 2, nil, nil) helper.mockEth.EthClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&evmtypes.Head{Number: blockHeight}, nil).Times(1) helper.mockEth.EthClient.On("FilterLogs", mock.Anything, mock.Anything).Return(nil, nil).Times(1) diff --git a/core/chains/evm/log/mocks/abigen_contract.go b/core/chains/evm/log/mocks/abigen_contract.go index 8dfea6b7564..dcc95a1acdb 100644 --- a/core/chains/evm/log/mocks/abigen_contract.go +++ b/core/chains/evm/log/mocks/abigen_contract.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -58,13 +58,12 @@ func (_m *AbigenContract) ParseLog(_a0 types.Log) (generated.AbigenLog, error) { return r0, r1 } -type mockConstructorTestingTNewAbigenContract interface { +// NewAbigenContract creates a new instance of AbigenContract. 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 NewAbigenContract(t interface { mock.TestingT Cleanup(func()) -} - -// NewAbigenContract creates a new instance of AbigenContract. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAbigenContract(t mockConstructorTestingTNewAbigenContract) *AbigenContract { +}) *AbigenContract { mock := &AbigenContract{} mock.Mock.Test(t) diff --git a/core/chains/evm/log/mocks/broadcast.go b/core/chains/evm/log/mocks/broadcast.go index 7366cd92e17..a58ce9f30e4 100644 --- a/core/chains/evm/log/mocks/broadcast.go +++ b/core/chains/evm/log/mocks/broadcast.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -167,13 +167,12 @@ func (_m *Broadcast) TransactionsRoot() common.Hash { return r0 } -type mockConstructorTestingTNewBroadcast interface { +// NewBroadcast creates a new instance of Broadcast. 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 NewBroadcast(t interface { mock.TestingT Cleanup(func()) -} - -// NewBroadcast creates a new instance of Broadcast. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBroadcast(t mockConstructorTestingTNewBroadcast) *Broadcast { +}) *Broadcast { mock := &Broadcast{} mock.Mock.Test(t) diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index a3bf2e84d31..84f143b39e4 100644 --- a/core/chains/evm/log/mocks/broadcaster.go +++ b/core/chains/evm/log/mocks/broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -229,13 +229,12 @@ func (_m *Broadcaster) WasAlreadyConsumed(lb log.Broadcast, qopts ...pg.QOpt) (b return r0, r1 } -type mockConstructorTestingTNewBroadcaster interface { +// NewBroadcaster creates a new instance of Broadcaster. 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 NewBroadcaster(t interface { mock.TestingT Cleanup(func()) -} - -// NewBroadcaster creates a new instance of Broadcaster. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBroadcaster(t mockConstructorTestingTNewBroadcaster) *Broadcaster { +}) *Broadcaster { mock := &Broadcaster{} mock.Mock.Test(t) diff --git a/core/chains/evm/log/orm_test.go b/core/chains/evm/log/orm_test.go index 70f400da457..365bb354338 100644 --- a/core/chains/evm/log/orm_test.go +++ b/core/chains/evm/log/orm_test.go @@ -26,7 +26,7 @@ func TestORM_broadcasts(t *testing.T) { orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) - _, addr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr := cltest.MustInsertRandomKey(t, ethKeyStore) specV2 := cltest.MustInsertV2JobSpec(t, db, addr) const selectQuery = `SELECT consumed FROM log_broadcasts @@ -165,10 +165,10 @@ func TestORM_MarkUnconsumed(t *testing.T) { orm := log.NewORM(db, lggr, cfg.Database(), cltest.FixtureChainID) - _, addr1 := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore) job1 := cltest.MustInsertV2JobSpec(t, db, addr1) - _, addr2 := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, addr2 := cltest.MustInsertRandomKey(t, ethKeyStore) job2 := cltest.MustInsertV2JobSpec(t, db, addr2) logBefore := cltest.RandomLog(t) diff --git a/core/chains/evm/log/registrations_test.go b/core/chains/evm/log/registrations_test.go index 350abfb916e..c9d4eba5898 100644 --- a/core/chains/evm/log/registrations_test.go +++ b/core/chains/evm/log/registrations_test.go @@ -49,8 +49,7 @@ func TestUnit_Registrations_InvariantViolations(t *testing.T) { // Different subscriber same jobID/contract address is not ok assert.Panics(t, func() { - opts := ListenerOpts{Contract: contractAddr, MinIncomingConfirmations: 1} - subError := &subscriber{l, opts} + subError := &subscriber{l, ListenerOpts{Contract: contractAddr, MinIncomingConfirmations: 1}} r.addSubscriber(subError) }) diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index d6fb2b7cb0d..4bcf1c50863 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -53,15 +53,15 @@ func (disabled) LogsWithSigs(start, end int64, eventSigs []common.Hash, address return nil, ErrDisabled } -func (disabled) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) { +func (disabled) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) { return nil, ErrDisabled } -func (disabled) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (disabled) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } @@ -73,38 +73,34 @@ func (d disabled) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, return nil, ErrDisabled } -func (disabled) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (disabled) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (disabled) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (disabled) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (disabled) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (d disabled) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (d disabled) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (d disabled) LogsCreatedAfter(eventSig common.Hash, address common.Address, time time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (d disabled) LogsCreatedAfter(eventSig common.Hash, address common.Address, time time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (d disabled) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (d disabled) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return nil, ErrDisabled } -func (d disabled) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) { +func (d disabled) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) { return 0, ErrDisabled } - -func (d disabled) LogsUntilBlockHashDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return nil, ErrDisabled -} diff --git a/core/chains/evm/logpoller/helper_test.go b/core/chains/evm/logpoller/helper_test.go index 4c764d7d74f..8415641c402 100644 --- a/core/chains/evm/logpoller/helper_test.go +++ b/core/chains/evm/logpoller/helper_test.go @@ -36,7 +36,7 @@ type TestHarness struct { Lggr logger.Logger // Chain2/ORM2 is just a dummy second chain, doesn't have a client. ChainID, ChainID2 *big.Int - ORM, ORM2 *logpoller.ORM + ORM, ORM2 *logpoller.DbORM LogPoller logpoller.LogPollerTest Client *backends.SimulatedBackend Owner *bind.TransactOpts @@ -45,7 +45,7 @@ type TestHarness struct { EthDB ethdb.Database } -func SetupTH(t testing.TB, finalityDepth, backfillBatchSize, rpcBatchSize int64) TestHarness { +func SetupTH(t testing.TB, useFinalityTag bool, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth int64) TestHarness { lggr := logger.TestLogger(t) chainID := testutils.NewRandomEVMChainID() chainID2 := testutils.NewRandomEVMChainID() @@ -63,7 +63,10 @@ func SetupTH(t testing.TB, finalityDepth, backfillBatchSize, rpcBatchSize int64) // Poll period doesn't matter, we intend to call poll and save logs directly in the test. // Set it to some insanely high value to not interfere with any tests. esc := client.NewSimulatedBackendClient(t, ec, chainID) - lp := logpoller.NewLogPoller(o, esc, lggr, 1*time.Hour, finalityDepth, backfillBatchSize, rpcBatchSize, 1000) + // Mark genesis block as finalized to avoid any nulls in the tests + head := esc.Backend().Blockchain().CurrentHeader() + esc.Backend().Blockchain().SetFinalized(head) + lp := logpoller.NewLogPoller(o, esc, lggr, 1*time.Hour, useFinalityTag, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth) emitterAddress1, _, emitter1, err := log_emitter.DeployLogEmitter(owner, ec) require.NoError(t, err) emitterAddress2, _, emitter2, err := log_emitter.DeployLogEmitter(owner, ec) diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index d6e55286029..54999cbdfb1 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -43,30 +43,37 @@ type LogPoller interface { // General querying Logs(start, end int64, eventSig common.Hash, address common.Address, qopts ...pg.QOpt) ([]Log, error) LogsWithSigs(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]Log, error) - LogsCreatedAfter(eventSig common.Hash, address common.Address, time time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) - LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) - LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) ([]Log, error) - LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) + LogsCreatedAfter(eventSig common.Hash, address common.Address, time time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) + LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) // Content based querying - IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) + IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) IndexedLogsByBlockRange(start, end int64, eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) - IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) + IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) - IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) - IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) - IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs int, qopts ...pg.QOpt) ([]Log, error) - LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) - LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) - LogsUntilBlockHashDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) + IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) } +type Confirmations int + +const ( + Finalized = Confirmations(-1) + Unconfirmed = Confirmations(0) +) + type LogPollerTest interface { LogPoller PollAndSaveLogs(ctx context.Context, currentBlockNumber int64) BackupPollAndSaveLogs(ctx context.Context, backupPollerBlockDelay int64) Filter(from, to *big.Int, bh *common.Hash) ethereum.FilterQuery GetReplayFromBlock(ctx context.Context, requested int64) (int64, error) + PruneOldBlocks(ctx context.Context) error } type Client interface { @@ -86,15 +93,16 @@ var ( type logPoller struct { utils.StartStopOnce - ec Client - orm *ORM - lggr logger.Logger - pollPeriod time.Duration // poll period set by block production rate - finalityDepth int64 // finality depth is taken to mean that block (head - finality) is finalized - keepBlocksDepth int64 // the number of blocks behind the head for which we keep the blocks. Must be greater than finality depth + 1. - backfillBatchSize int64 // batch size to use when backfilling finalized logs - rpcBatchSize int64 // batch size to use for fallback RPC calls made in GetBlocks - backupPollerNextBlock int64 + ec Client + orm ORM + lggr logger.Logger + pollPeriod time.Duration // poll period set by block production rate + useFinalityTag bool // indicates whether logPoller should use chain's finality or pick a fixed depth for finality + finalityDepth int64 // finality depth is taken to mean that block (head - finality) is finalized. If `useFinalityTag` is set to true, this value is ignored, because finalityDepth is fetched from chain + keepFinalizedBlocksDepth int64 // the number of blocks behind the last finalized block we keep in database + backfillBatchSize int64 // batch size to use when backfilling finalized logs + rpcBatchSize int64 // batch size to use for fallback RPC calls made in GetBlocks + backupPollerNextBlock int64 filterMu sync.RWMutex filters map[string]Filter @@ -119,22 +127,23 @@ type logPoller struct { // // How fast that can be done depends largely on network speed and DB, but even for the fastest // support chain, polygon, which has 2s block times, we need RPCs roughly with <= 500ms latency -func NewLogPoller(orm *ORM, ec Client, lggr logger.Logger, pollPeriod time.Duration, - finalityDepth int64, backfillBatchSize int64, rpcBatchSize int64, keepBlocksDepth int64) *logPoller { +func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, pollPeriod time.Duration, + useFinalityTag bool, finalityDepth int64, backfillBatchSize int64, rpcBatchSize int64, keepFinalizedBlocksDepth int64) *logPoller { return &logPoller{ - ec: ec, - orm: orm, - lggr: lggr.Named("LogPoller"), - replayStart: make(chan int64), - replayComplete: make(chan error), - pollPeriod: pollPeriod, - finalityDepth: finalityDepth, - backfillBatchSize: backfillBatchSize, - rpcBatchSize: rpcBatchSize, - keepBlocksDepth: keepBlocksDepth, - filters: make(map[string]Filter), - filterDirty: true, // Always build Filter on first call to cache an empty filter if nothing registered yet. + ec: ec, + orm: orm, + lggr: lggr.Named("LogPoller"), + replayStart: make(chan int64), + replayComplete: make(chan error), + pollPeriod: pollPeriod, + finalityDepth: finalityDepth, + useFinalityTag: useFinalityTag, + backfillBatchSize: backfillBatchSize, + rpcBatchSize: rpcBatchSize, + keepFinalizedBlocksDepth: keepFinalizedBlocksDepth, + filters: make(map[string]Filter), + filterDirty: true, // Always build Filter on first call to cache an empty filter if nothing registered yet. } } @@ -369,11 +378,6 @@ func (lp *logPoller) ReplayAsync(fromBlock int64) { } func (lp *logPoller) Start(parentCtx context.Context) error { - if lp.keepBlocksDepth < (lp.finalityDepth + 1) { - // We add 1 since for reorg detection on the first unfinalized block - // we need to keep 1 finalized block. - return errors.Errorf("keepBlocksDepth %d must be greater than finality %d + 1", lp.keepBlocksDepth, lp.finalityDepth) - } return lp.StartOnce("LogPoller", func() error { ctx, cancel := context.WithCancel(parentCtx) lp.ctx = ctx @@ -401,7 +405,7 @@ func (lp *logPoller) Name() string { } func (lp *logPoller) HealthReport() map[string]error { - return map[string]error{lp.Name(): lp.StartStopOnce.Healthy()} + return map[string]error{lp.Name(): lp.Healthy()} } func (lp *logPoller) GetReplayFromBlock(ctx context.Context, requested int64) (int64, error) { @@ -495,21 +499,20 @@ func (lp *logPoller) run() { } // Otherwise this is the first poll _ever_ on a new chain. // Only safe thing to do is to start at the first finalized block. - latest, err := lp.ec.HeadByNumber(lp.ctx, nil) + latestBlock, latestFinalizedBlockNumber, err := lp.latestBlocks(lp.ctx) if err != nil { lp.lggr.Warnw("Unable to get latest for first poll", "err", err) continue } - latestNum := latest.Number // Do not support polling chains which don't even have finality depth worth of blocks. // Could conceivably support this but not worth the effort. - // Need finality depth + 1, no block 0. - if latestNum <= lp.finalityDepth { - lp.lggr.Warnw("Insufficient number of blocks on chain, waiting for finality depth", "err", err, "latest", latestNum, "finality", lp.finalityDepth) + // Need last finalized block number to be higher than 0 + if latestFinalizedBlockNumber <= 0 { + lp.lggr.Warnw("Insufficient number of blocks on chain, waiting for finality depth", "err", err, "latest", latestBlock.Number) continue } // Starting at the first finalized block. We do not backfill the first finalized block. - start = latestNum - lp.finalityDepth + start = latestFinalizedBlockNumber } else { start = lastProcessed.BlockNumber + 1 } @@ -533,7 +536,7 @@ func (lp *logPoller) run() { lp.BackupPollAndSaveLogs(lp.ctx, backupPollerBlockDelay) case <-blockPruneTick: blockPruneTick = time.After(utils.WithJitter(lp.pollPeriod * 1000)) - if err := lp.pruneOldBlocks(lp.ctx); err != nil { + if err := lp.PruneOldBlocks(lp.ctx); err != nil { lp.lggr.Errorw("Unable to prune old blocks", "err", err) } case <-logPruneTick: @@ -556,22 +559,19 @@ func (lp *logPoller) BackupPollAndSaveLogs(ctx context.Context, backupPollerBloc } return } - - // If this is our first run, start max(finalityDepth+1, backupPollerBlockDelay) blocks behind the last processed + // If this is our first run, start from block min(lastProcessed.FinalizedBlockNumber-1, lastProcessed.BlockNumber-backupPollerBlockDelay) + backupStartBlock := mathutil.Min(lastProcessed.FinalizedBlockNumber-1, lastProcessed.BlockNumber-backupPollerBlockDelay) // (or at block 0 if whole blockchain is too short) - lp.backupPollerNextBlock = lastProcessed.BlockNumber - mathutil.Max(lp.finalityDepth+1, backupPollerBlockDelay) - if lp.backupPollerNextBlock < 0 { - lp.backupPollerNextBlock = 0 - } + lp.backupPollerNextBlock = mathutil.Max(backupStartBlock, 0) } - latestBlock, err := lp.ec.HeadByNumber(ctx, nil) + _, latestFinalizedBlockNumber, err := lp.latestBlocks(ctx) if err != nil { lp.lggr.Warnw("Backup logpoller failed to get latest block", "err", err) return } - lastSafeBackfillBlock := latestBlock.Number - lp.finalityDepth - 1 + lastSafeBackfillBlock := latestFinalizedBlockNumber - 1 if lastSafeBackfillBlock >= lp.backupPollerNextBlock { lp.lggr.Infow("Backup poller backfilling logs", "start", lp.backupPollerNextBlock, "end", lastSafeBackfillBlock) if err = lp.backfill(ctx, lp.backupPollerNextBlock, lastSafeBackfillBlock); err != nil { @@ -676,7 +676,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } lp.lggr.Debugw("Backfill found logs", "from", from, "to", to, "logs", len(gethLogs), "blocks", blocks) - err = lp.orm.q.WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { + err = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { return lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithQueryer(tx)) }) if err != nil { @@ -733,7 +733,7 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // There can be another reorg while we're finding the LCA. // That is ok, since we'll detect it on the next iteration. // Since we go currentBlock by currentBlock for unfinalized logs, the mismatch starts at currentBlockNumber - 1. - blockAfterLCA, err2 := lp.findBlockAfterLCA(ctx, currentBlock) + blockAfterLCA, err2 := lp.findBlockAfterLCA(ctx, currentBlock, expectedParent.FinalizedBlockNumber) if err2 != nil { lp.lggr.Warnw("Unable to find LCA after reorg, retrying", "err", err2) return nil, errors.New("Unable to find LCA after reorg, retrying") @@ -747,7 +747,7 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // the canonical set per read. Typically, if an application took action on a log // it would be saved elsewhere e.g. evm.txes, so it seems better to just support the fast reads. // Its also nicely analogous to reading from the chain itself. - err2 = lp.orm.q.WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { + err2 = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { // These deletes are bounded by reorg depth, so they are // fast and should not slow down the log readers. err3 := lp.orm.DeleteBlocksAfter(blockAfterLCA.Number, pg.WithQueryer(tx)) @@ -778,7 +778,9 @@ func (lp *logPoller) getCurrentBlockMaybeHandleReorg(ctx context.Context, curren // conditions this would be equal to lastProcessed.BlockNumber + 1. func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int64) { lp.lggr.Debugw("Polling for logs", "currentBlockNumber", currentBlockNumber) - latestBlock, err := lp.ec.HeadByNumber(ctx, nil) + // Intentionally not using logPoller.finalityDepth directly but the latestFinalizedBlockNumber returned from lp.latestBlocks() + // latestBlocks knows how to pick a proper latestFinalizedBlockNumber based on the logPoller's configuration + latestBlock, latestFinalizedBlockNumber, err := lp.latestBlocks(ctx) if err != nil { lp.lggr.Warnw("Unable to get latestBlockNumber block", "err", err, "currentBlockNumber", currentBlockNumber) return @@ -811,7 +813,7 @@ func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int // E.g. 1<-2<-3(currentBlockNumber)<-4<-5<-6<-7(latestBlockNumber), finality is 2. So 3,4 can be batched. // Although 5 is finalized, we still need to save it to the db for reorg detection if 6 is a reorg. // start = currentBlockNumber = 3, end = latestBlockNumber - finality - 1 = 7-2-1 = 4 (inclusive range). - lastSafeBackfillBlock := latestBlockNumber - lp.finalityDepth - 1 + lastSafeBackfillBlock := latestFinalizedBlockNumber - 1 if lastSafeBackfillBlock >= currentBlockNumber { lp.lggr.Infow("Backfilling logs", "start", currentBlockNumber, "end", lastSafeBackfillBlock) if err = lp.backfill(ctx, currentBlockNumber, lastSafeBackfillBlock); err != nil { @@ -844,8 +846,8 @@ func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int return } lp.lggr.Debugw("Unfinalized log query", "logs", len(logs), "currentBlockNumber", currentBlockNumber, "blockHash", currentBlock.Hash, "timestamp", currentBlock.Timestamp.Unix()) - err = lp.orm.q.WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { - if err2 := lp.orm.InsertBlock(h, currentBlockNumber, currentBlock.Timestamp, pg.WithQueryer(tx)); err2 != nil { + err = lp.orm.Q().WithOpts(pg.WithParentCtx(ctx)).Transaction(func(tx pg.Queryer) error { + if err2 := lp.orm.InsertBlock(h, currentBlockNumber, currentBlock.Timestamp, latestFinalizedBlockNumber, pg.WithQueryer(tx)); err2 != nil { return err2 } if len(logs) == 0 { @@ -879,9 +881,37 @@ func (lp *logPoller) PollAndSaveLogs(ctx context.Context, currentBlockNumber int } } +// Returns information about latestBlock, latestFinalizedBlockNumber +// If finality tag is not enabled, latestFinalizedBlockNumber is calculated as latestBlockNumber - lp.finalityDepth (configured param) +// Otherwise, we return last finalized block number returned from chain +func (lp *logPoller) latestBlocks(ctx context.Context) (*evmtypes.Head, int64, error) { + // If finality is not enabled, we can only fetch the latest block + if !lp.useFinalityTag { + // Example: + // finalityDepth = 2 + // Blocks: 1->2->3->4->5(latestBlock) + // latestFinalizedBlockNumber would be 3 + latestBlock, err := lp.ec.HeadByNumber(ctx, nil) + if err != nil { + return nil, 0, err + } + // If chain has fewer blocks than finalityDepth, return 0 + return latestBlock, mathutil.Max(latestBlock.Number-lp.finalityDepth, 0), nil + } + + // If finality is enabled, we need to get the latest and finalized blocks. + blocks, err := lp.batchFetchBlocks(ctx, []string{rpc.LatestBlockNumber.String(), rpc.FinalizedBlockNumber.String()}, 2) + if err != nil { + return nil, 0, err + } + latest := blocks[0] + finalized := blocks[1] + return latest, finalized.Number, nil +} + // Find the first place where our chain and their chain have the same block, // that block number is the LCA. Return the block after that, where we want to resume polling. -func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.Head) (*evmtypes.Head, error) { +func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.Head, latestFinalizedBlockNumber int64) (*evmtypes.Head, error) { // Current is where the mismatch starts. // Check its parent to see if its the same as ours saved. parent, err := lp.ec.HeadByHash(ctx, current.ParentHash) @@ -889,12 +919,11 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He return nil, err } blockAfterLCA := *current - reorgStart := parent.Number - // We expect reorgs up to the block after (current - finalityDepth), - // since the block at (current - finalityDepth) is finalized. + // We expect reorgs up to the block after latestFinalizedBlock // We loop via parent instead of current so current always holds the LCA+1. // If the parent block number becomes < the first finalized block our reorg is too deep. - for parent.Number >= (reorgStart - lp.finalityDepth) { + // This can happen only if finalityTag is not enabled and fixed finalityDepth is provided via config. + for parent.Number >= latestFinalizedBlockNumber { ourParentBlockHash, err := lp.orm.SelectBlockByNumber(parent.Number, pg.WithParentCtx(ctx)) if err != nil { return nil, err @@ -910,55 +939,56 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He return nil, err } } - lp.lggr.Criticalw("Reorg greater than finality depth detected", "max reorg depth", lp.finalityDepth-1) + lp.lggr.Criticalw("Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) rerr := errors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) return nil, rerr } -// pruneOldBlocks removes blocks that are > lp.ancientBlockDepth behind the head. -func (lp *logPoller) pruneOldBlocks(ctx context.Context) error { - latest, err := lp.ec.HeadByNumber(ctx, nil) +// PruneOldBlocks removes blocks that are > lp.keepFinalizedBlocksDepth behind the latest finalized block. +func (lp *logPoller) PruneOldBlocks(ctx context.Context) error { + latestBlock, err := lp.orm.SelectLatestBlock(pg.WithParentCtx(ctx)) if err != nil { return err } - if latest == nil { - return errors.Errorf("received nil block from RPC") + if latestBlock == nil { + // No blocks saved yet. + return nil } - if latest.Number <= lp.keepBlocksDepth { + if latestBlock.FinalizedBlockNumber <= lp.keepFinalizedBlocksDepth { // No-op, keep all blocks return nil } - // 1-2-3-4-5(latest), keepBlocksDepth=3 + // 1-2-3-4-5(finalized)-6-7(latest), keepFinalizedBlocksDepth=3 // Remove <= 2 - return lp.orm.DeleteBlocksBefore(latest.Number-lp.keepBlocksDepth, pg.WithParentCtx(ctx)) + return lp.orm.DeleteBlocksBefore(latestBlock.FinalizedBlockNumber-lp.keepFinalizedBlocksDepth, pg.WithParentCtx(ctx)) } // Logs returns logs matching topics and address (exactly) in the given block range, // which are canonical at time of query. func (lp *logPoller) Logs(start, end int64, eventSig common.Hash, address common.Address, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectLogsByBlockRangeFilter(start, end, address, eventSig, qopts...) + return lp.orm.SelectLogs(start, end, address, eventSig, qopts...) } func (lp *logPoller) LogsWithSigs(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectLogsWithSigsByBlockRangeFilter(start, end, address, eventSigs, qopts...) + return lp.orm.SelectLogsWithSigs(start, end, address, eventSigs, qopts...) } -func (lp *logPoller) LogsCreatedAfter(eventSig common.Hash, address common.Address, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectLogsCreatedAfter(eventSig[:], address, after, confs, qopts...) +func (lp *logPoller) LogsCreatedAfter(eventSig common.Hash, address common.Address, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectLogsCreatedAfter(address, eventSig, after, confs, qopts...) } // IndexedLogs finds all the logs that have a topic value in topicValues at index topicIndex. -func (lp *logPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (lp *logPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return lp.orm.SelectIndexedLogs(address, eventSig, topicIndex, topicValues, confs, qopts...) } // IndexedLogsByBlockRange finds all the logs that have a topic value in topicValues at index topicIndex within the block range func (lp *logPoller) IndexedLogsByBlockRange(start, end int64, eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectIndexedLogsByBlockRangeFilter(start, end, address, eventSig, topicIndex, topicValues, qopts...) + return lp.orm.SelectIndexedLogsByBlockRange(start, end, address, eventSig, topicIndex, topicValues, qopts...) } -func (lp *logPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (lp *logPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return lp.orm.SelectIndexedLogsCreatedAfter(address, eventSig, topicIndex, topicValues, after, confs, qopts...) } @@ -967,29 +997,23 @@ func (lp *logPoller) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Has } // LogsDataWordGreaterThan note index is 0 based. -func (lp *logPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectDataWordGreaterThan(address, eventSig, wordIndex, wordValueMin, confs, qopts...) +func (lp *logPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectLogsDataWordGreaterThan(address, eventSig, wordIndex, wordValueMin, confs, qopts...) } // LogsDataWordRange note index is 0 based. -func (lp *logPoller) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectDataWordRange(address, eventSig, wordIndex, wordValueMin, wordValueMax, confs, qopts...) +func (lp *logPoller) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectLogsDataWordRange(address, eventSig, wordIndex, wordValueMin, wordValueMax, confs, qopts...) } // IndexedLogsTopicGreaterThan finds all the logs that have a topic value greater than topicValueMin at index topicIndex. // Only works for integer topics. -func (lp *logPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectIndexLogsTopicGreaterThan(address, eventSig, topicIndex, topicValueMin, confs, qopts...) +func (lp *logPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectIndexedLogsTopicGreaterThan(address, eventSig, topicIndex, topicValueMin, confs, qopts...) } -// LogsUntilBlockHashDataWordGreaterThan note index is 0 based. -// If the blockhash is not found (i.e. a stale fork) it will error. -func (lp *logPoller) LogsUntilBlockHashDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectUntilBlockHashDataWordGreaterThan(address, eventSig, wordIndex, wordValueMin, untilBlockHash, qopts...) -} - -func (lp *logPoller) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return lp.orm.SelectIndexLogsTopicRange(address, eventSig, topicIndex, topicValueMin, topicValueMax, confs, qopts...) +func (lp *logPoller) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return lp.orm.SelectIndexedLogsTopicRange(address, eventSig, topicIndex, topicValueMin, topicValueMax, confs, qopts...) } // LatestBlock returns the latest block the log poller is on. It tracks blocks to be able @@ -1008,16 +1032,16 @@ func (lp *logPoller) BlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, } // LatestLogByEventSigWithConfs finds the latest log that has confs number of blocks on top of the log. -func (lp *logPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) { - return lp.orm.SelectLatestLogEventSigWithConfs(eventSig, address, confs, qopts...) +func (lp *logPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) { + return lp.orm.SelectLatestLogByEventSigWithConfs(eventSig, address, confs, qopts...) } -func (lp *logPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (lp *logPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return lp.orm.SelectLatestLogEventSigsAddrsWithConfs(fromBlock, addresses, eventSigs, confs, qopts...) } -func (lp *logPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) { - return lp.orm.SelectLatestBlockNumberEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) +func (lp *logPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) { + return lp.orm.SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) } // GetBlocksRange tries to get the specified block numbers from the log pollers @@ -1039,9 +1063,9 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts // Retrieve all blocks within this range from the log poller. blocksFound := make(map[uint64]LogPollerBlock) qopts = append(qopts, pg.WithParentCtx(ctx)) - minRequestedBlock := mathutil.Min(numbers[0], numbers[1:]...) - maxRequestedBlock := mathutil.Max(numbers[0], numbers[1:]...) - lpBlocks, err := lp.orm.GetBlocksRange(minRequestedBlock, maxRequestedBlock, qopts...) + minRequestedBlock := int64(mathutil.Min(numbers[0], numbers[1:]...)) + maxRequestedBlock := int64(mathutil.Max(numbers[0], numbers[1:]...)) + lpBlocks, err := lp.orm.GetBlocksRange(int64(minRequestedBlock), int64(maxRequestedBlock), qopts...) if err != nil { lp.lggr.Warnw("Error while retrieving blocks from log pollers blocks table. Falling back to RPC...", "requestedBlocks", numbers, "err", err) } else { @@ -1084,17 +1108,10 @@ func (lp *logPoller) fillRemainingBlocksFromRPC( blocksRequested map[uint64]struct{}, blocksFound map[uint64]LogPollerBlock, ) (map[uint64]LogPollerBlock, error) { - var reqs []rpc.BatchElem - var remainingBlocks []uint64 + var remainingBlocks []string for num := range blocksRequested { if _, ok := blocksFound[num]; !ok { - req := rpc.BatchElem{ - Method: "eth_getBlockByNumber", - Args: []interface{}{hexutil.EncodeBig(big.NewInt(0).SetUint64(num)), false}, - Result: &evmtypes.Head{}, - } - reqs = append(reqs, req) - remainingBlocks = append(remainingBlocks, num) + remainingBlocks = append(remainingBlocks, hexutil.EncodeBig(new(big.Int).SetUint64(num))) } } @@ -1103,8 +1120,37 @@ func (lp *logPoller) fillRemainingBlocksFromRPC( "remainingBlocks", remainingBlocks) } - for i := 0; i < len(reqs); i += int(lp.rpcBatchSize) { - j := i + int(lp.rpcBatchSize) + evmBlocks, err := lp.batchFetchBlocks(ctx, remainingBlocks, lp.rpcBatchSize) + if err != nil { + return nil, err + } + + logPollerBlocks := make(map[uint64]LogPollerBlock) + for _, head := range evmBlocks { + logPollerBlocks[uint64(head.Number)] = LogPollerBlock{ + EvmChainId: head.EVMChainID, + BlockHash: head.Hash, + BlockNumber: head.Number, + BlockTimestamp: head.Timestamp, + CreatedAt: head.Timestamp, + } + } + return logPollerBlocks, nil +} + +func (lp *logPoller) batchFetchBlocks(ctx context.Context, blocksRequested []string, batchSize int64) ([]*evmtypes.Head, error) { + reqs := make([]rpc.BatchElem, 0, len(blocksRequested)) + for _, num := range blocksRequested { + req := rpc.BatchElem{ + Method: "eth_getBlockByNumber", + Args: []interface{}{num, false}, + Result: &evmtypes.Head{}, + } + reqs = append(reqs, req) + } + + for i := 0; i < len(reqs); i += int(batchSize) { + j := i + int(batchSize) if j > len(reqs) { j = len(reqs) } @@ -1115,7 +1161,7 @@ func (lp *logPoller) fillRemainingBlocksFromRPC( } } - var blocksFoundFromRPC = make(map[uint64]LogPollerBlock) + var blocks = make([]*evmtypes.Head, 0, len(reqs)) for _, r := range reqs { if r.Error != nil { return nil, r.Error @@ -1134,23 +1180,17 @@ func (lp *logPoller) fillRemainingBlocksFromRPC( if block.Number < 0 { return nil, errors.Errorf("expected block number to be >= to 0, got %d", block.Number) } - blocksFoundFromRPC[uint64(block.Number)] = LogPollerBlock{ - EvmChainId: block.EVMChainID, - BlockHash: block.Hash, - BlockNumber: block.Number, - BlockTimestamp: block.Timestamp, - CreatedAt: block.Timestamp, - } + blocks = append(blocks, block) } - return blocksFoundFromRPC, nil + return blocks, nil } // IndexedLogsWithSigsExcluding returns the set difference(A-B) of logs with signature sigA and sigB, matching is done on the topics index // // For example, query to retrieve unfulfilled requests by querying request log events without matching fulfillment log events. // The order of events is not significant. Both logs must be inside the block range and have the minimum number of confirmations -func (lp *logPoller) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs int, qopts ...pg.QOpt) ([]Log, error) { +func (lp *logPoller) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { return lp.orm.SelectIndexedLogsWithSigsExcluding(eventSigA, eventSigB, topicIndex, address, fromBlock, toBlock, confs, qopts...) } diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index 5f1c21a5b81..b9474158a6b 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -2,7 +2,9 @@ package logpoller import ( "context" + "fmt" "math/big" + "reflect" "strings" "sync" "testing" @@ -11,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -24,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -31,7 +35,7 @@ var ( ) // Validate that filters stored in log_filters_table match the filters stored in memory -func validateFiltersTable(t *testing.T, lp *logPoller, orm *ORM) { +func validateFiltersTable(t *testing.T, lp *logPoller, orm *DbORM) { filters, err := orm.LoadFilters() require.NoError(t, err) require.Equal(t, len(filters), len(lp.filters)) @@ -57,7 +61,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) // Set up a test chain with a log emitting contract deployed. - lp := NewLogPoller(orm, nil, lggr, time.Hour, 1, 1, 2, 1000) + lp := NewLogPoller(orm, nil, lggr, time.Hour, false, 1, 1, 2, 1000) // We expect a zero Filter if nothing registered yet. f := lp.Filter(nil, nil, nil) @@ -211,7 +215,7 @@ func TestLogPoller_BackupPollerStartup(t *testing.T) { ctx := testutils.Context(t) - lp := NewLogPoller(orm, ec, lggr, 1*time.Hour, 2, 3, 2, 1000) + lp := NewLogPoller(orm, ec, lggr, 1*time.Hour, false, 2, 3, 2, 1000) lp.BackupPollAndSaveLogs(ctx, 100) assert.Equal(t, int64(0), lp.backupPollerNextBlock) assert.Equal(t, 1, observedLogs.FilterMessageSnippet("ran before first successful log poller run").Len()) @@ -252,7 +256,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Once() ec.On("ConfiguredChainID").Return(chainID, nil) - lp := NewLogPoller(orm, ec, lggr, time.Hour, 3, 3, 3, 20) + lp := NewLogPoller(orm, ec, lggr, time.Hour, false, 3, 3, 3, 20) // process 1 log in block 3 lp.PollAndSaveLogs(tctx, 4) @@ -456,9 +460,80 @@ func TestLogPoller_Replay(t *testing.T) { }) } +func Test_latestBlockAndFinalityDepth(t *testing.T) { + tctx := testutils.Context(t) + lggr, _ := logger.TestLoggerObserved(t, zapcore.ErrorLevel) + chainID := testutils.FixtureChainID + db := pgtest.NewSqlxDB(t) + orm := NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + + t.Run("pick latest block from chain and use finality from config with finality disabled", func(t *testing.T) { + head := evmtypes.Head{Number: 4} + finalityDepth := int64(3) + ec := evmclimocks.NewClient(t) + ec.On("HeadByNumber", mock.Anything, mock.Anything).Return(&head, nil) + + lp := NewLogPoller(orm, ec, lggr, time.Hour, false, finalityDepth, 3, 3, 20) + latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(tctx) + require.NoError(t, err) + require.Equal(t, latestBlock.Number, head.Number) + require.Equal(t, finalityDepth, latestBlock.Number-lastFinalizedBlockNumber) + }) + + t.Run("finality tags in use", func(t *testing.T) { + t.Run("client returns data properly", func(t *testing.T) { + expectedLatestBlockNumber := int64(20) + expectedLastFinalizedBlockNumber := int64(12) + ec := evmclimocks.NewClient(t) + ec.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { + return len(b) == 2 && + reflect.DeepEqual(b[0].Args, []interface{}{"latest", false}) && + reflect.DeepEqual(b[1].Args, []interface{}{"finalized", false}) + })).Return(nil).Run(func(args mock.Arguments) { + elems := args.Get(1).([]rpc.BatchElem) + // Latest block details + *(elems[0].Result.(*evmtypes.Head)) = evmtypes.Head{Number: expectedLatestBlockNumber, Hash: utils.RandomBytes32()} + // Finalized block details + *(elems[1].Result.(*evmtypes.Head)) = evmtypes.Head{Number: expectedLastFinalizedBlockNumber, Hash: utils.RandomBytes32()} + }) + + lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) + + latestBlock, lastFinalizedBlockNumber, err := lp.latestBlocks(tctx) + require.NoError(t, err) + require.Equal(t, expectedLatestBlockNumber, latestBlock.Number) + require.Equal(t, expectedLastFinalizedBlockNumber, lastFinalizedBlockNumber) + }) + + t.Run("client returns error for at least one of the calls", func(t *testing.T) { + ec := evmclimocks.NewClient(t) + ec.On("BatchCallContext", mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { + elems := args.Get(1).([]rpc.BatchElem) + // Latest block details + *(elems[0].Result.(*evmtypes.Head)) = evmtypes.Head{Number: 10} + // Finalized block details + elems[1].Error = fmt.Errorf("some error") + }) + + lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) + _, _, err := lp.latestBlocks(tctx) + require.Error(t, err) + }) + + t.Run("BatchCall returns an error", func(t *testing.T) { + ec := evmclimocks.NewClient(t) + ec.On("BatchCallContext", mock.Anything, mock.Anything).Return(fmt.Errorf("some error")) + + lp := NewLogPoller(orm, ec, lggr, time.Hour, true, 3, 3, 3, 20) + _, _, err := lp.latestBlocks(tctx) + require.Error(t, err) + }) + }) +} + func benchmarkFilter(b *testing.B, nFilters, nAddresses, nEvents int) { lggr := logger.TestLogger(b) - lp := NewLogPoller(nil, nil, lggr, 1*time.Hour, 2, 3, 2, 1000) + lp := NewLogPoller(nil, nil, lggr, 1*time.Hour, false, 2, 3, 2, 1000) for i := 0; i < nFilters; i++ { var addresses []common.Address var events []common.Hash diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index c434d18c999..1ee8f4dcb78 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -3,6 +3,7 @@ package logpoller_test import ( "context" "fmt" + "math" "math/big" "testing" "time" @@ -39,23 +40,17 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func logRuntime(t *testing.T, start time.Time) { +func logRuntime(t testing.TB, start time.Time) { t.Log("runtime", time.Since(start)) } -func TestPopulateLoadedDB(t *testing.T) { - t.Skip("Only for local load testing and query analysis") - lggr := logger.TestLogger(t) - _, db := heavyweight.FullTestDBV2(t, "logs_scale", nil) - chainID := big.NewInt(137) - - o := logpoller.NewORM(big.NewInt(137), db, lggr, pgtest.NewQConfig(true)) +func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (common.Hash, common.Address, common.Address) { event1 := EmitterABI.Events["Log1"].ID address1 := common.HexToAddress("0x2ab9a2Dc53736b361b72d900CdF9F78F9406fbbb") address2 := common.HexToAddress("0x6E225058950f237371261C985Db6bDe26df2200E") + startDate := time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC) - // We start at 1 just so block number > 0 - for j := 1; j < 1000; j++ { + for j := 1; j < 100; j++ { var logs []logpoller.Log // Max we can insert per batch for i := 0; i < 1000; i++ { @@ -63,23 +58,60 @@ func TestPopulateLoadedDB(t *testing.T) { if (i+(1000*j))%2 == 0 { addr = address2 } + blockNumber := int64(i + (1000 * j)) + blockTimestamp := startDate.Add(time.Duration(j*1000) * time.Hour) + logs = append(logs, logpoller.Log{ - EvmChainId: utils.NewBig(chainID), - LogIndex: 1, - BlockHash: common.HexToHash(fmt.Sprintf("0x%d", i+(1000*j))), - BlockNumber: int64(i + (1000 * j)), - EventSig: event1, - Topics: [][]byte{event1[:], logpoller.EvmWord(uint64(i + 1000*j)).Bytes()}, - Address: addr, - TxHash: common.HexToHash("0x1234"), - Data: logpoller.EvmWord(uint64(i + 1000*j)).Bytes(), + EvmChainId: utils.NewBig(chainID), + LogIndex: 1, + BlockHash: common.HexToHash(fmt.Sprintf("0x%d", i+(1000*j))), + BlockNumber: blockNumber, + BlockTimestamp: blockTimestamp, + EventSig: event1, + Topics: [][]byte{event1[:], logpoller.EvmWord(uint64(i + 1000*j)).Bytes()}, + Address: addr, + TxHash: utils.RandomAddress().Hash(), + Data: logpoller.EvmWord(uint64(i + 1000*j)).Bytes(), + CreatedAt: blockTimestamp, }) + } require.NoError(t, o.InsertLogs(logs)) + require.NoError(t, o.InsertBlock(utils.RandomAddress().Hash(), int64((j+1)*1000-1), startDate.Add(time.Duration(j*1000)*time.Hour), 0)) } + + return event1, address1, address2 +} + +func BenchmarkSelectLogsCreatedAfter(b *testing.B) { + chainId := big.NewInt(137) + _, db := heavyweight.FullTestDBV2(b, "logs_scale", nil) + o := logpoller.NewORM(chainId, db, logger.TestLogger(b), pgtest.NewQConfig(false)) + event, address, _ := populateDatabase(b, o, chainId) + + // Setting searchDate to pick around 5k logs + searchDate := time.Date(2020, 1, 1, 12, 12, 12, 0, time.UTC) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + logs, err := o.SelectLogsCreatedAfter(address, event, searchDate, 500) + require.NotZero(b, len(logs)) + require.NoError(b, err) + } +} + +func TestPopulateLoadedDB(t *testing.T) { + t.Skip("Only for local load testing and query analysis") + _, db := heavyweight.FullTestDBV2(t, "logs_scale", nil) + chainID := big.NewInt(137) + + o := logpoller.NewORM(big.NewInt(137), db, logger.TestLogger(t), pgtest.NewQConfig(true)) + event1, address1, address2 := populateDatabase(t, o, chainID) + func() { defer logRuntime(t, time.Now()) - _, err1 := o.SelectLogsByBlockRangeFilter(750000, 800000, address1, event1) + _, err1 := o.SelectLogs(750000, 800000, address1, event1) require.NoError(t, err1) }() func() { @@ -89,10 +121,10 @@ func TestPopulateLoadedDB(t *testing.T) { }() // Confirm all the logs. - require.NoError(t, o.InsertBlock(common.HexToHash("0x10"), 1000000, time.Now())) + require.NoError(t, o.InsertBlock(common.HexToHash("0x10"), 1000000, time.Now(), 0)) func() { defer logRuntime(t, time.Now()) - lgs, err1 := o.SelectDataWordRange(address1, event1, 0, logpoller.EvmWord(500000), logpoller.EvmWord(500020), 0) + lgs, err1 := o.SelectLogsDataWordRange(address1, event1, 0, logpoller.EvmWord(500000), logpoller.EvmWord(500020), 0) require.NoError(t, err1) // 10 since every other log is for address1 assert.Equal(t, 10, len(lgs)) @@ -107,18 +139,17 @@ func TestPopulateLoadedDB(t *testing.T) { func() { defer logRuntime(t, time.Now()) - lgs, err1 := o.SelectIndexLogsTopicRange(address1, event1, 1, logpoller.EvmWord(500000), logpoller.EvmWord(500020), 0) + lgs, err1 := o.SelectIndexedLogsTopicRange(address1, event1, 1, logpoller.EvmWord(500000), logpoller.EvmWord(500020), 0) require.NoError(t, err1) assert.Equal(t, 10, len(lgs)) }() } func TestLogPoller_Integration(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) th.Client.Commit() // Block 2. Ensure we have finality number of blocks - err := th.LogPoller.RegisterFilter(logpoller.Filter{"Integration test", []common.Hash{EmitterABI.Events["Log1"].ID}, []common.Address{th.EmitterAddress1}, 0}) - require.NoError(t, err) + require.NoError(t, th.LogPoller.RegisterFilter(logpoller.Filter{"Integration test", []common.Hash{EmitterABI.Events["Log1"].ID}, []common.Address{th.EmitterAddress1}, 0})) require.Len(t, th.LogPoller.Filter(nil, nil, nil).Addresses, 1) require.Len(t, th.LogPoller.Filter(nil, nil, nil).Topics, 1) @@ -149,9 +180,9 @@ func TestLogPoller_Integration(t *testing.T) { // Once the backup poller runs we should also have the log from block 3 testutils.AssertEventually(t, func() bool { - logs, err := th.LogPoller.Logs(3, 3, EmitterABI.Events["Log1"].ID, th.EmitterAddress1) - require.NoError(t, err) - return len(logs) == 1 + l, err2 := th.LogPoller.Logs(3, 3, EmitterABI.Events["Log1"].ID, th.EmitterAddress1) + require.NoError(t, err2) + return len(l) == 1 }) // Now let's update the Filter and replay to get Log2 logs. @@ -190,149 +221,344 @@ func TestLogPoller_Integration(t *testing.T) { // for the same block hash. We should be able to handle this without missing any logs, as // long as the logs returned for finalized blocks are consistent. func Test_BackupLogPoller(t *testing.T) { - th := SetupTH(t, 2, 3, 2) - // later, we will need at least 32 blocks filled with logs for cache invalidation - for i := int64(0); i < 32; i++ { - // to invalidate geth's internal read-cache, a matching log must be found in the bloom Filter - // for each of the 32 blocks - tx, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(i + 7)}) - require.NoError(t, err) - require.NotNil(t, tx) - th.Client.Commit() + tests := []struct { + name string + finalityDepth int64 + finalityTag bool + }{ + { + name: "fixed finality depth without finality tag", + finalityDepth: 2, + finalityTag: false, + }, + { + name: "chain finality in use", + finalityDepth: 0, + finalityTag: true, + }, } - ctx := testutils.Context(t) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, tt.finalityTag, tt.finalityDepth, 3, 2, 1000) + // later, we will need at least 32 blocks filled with logs for cache invalidation + for i := int64(0); i < 32; i++ { + // to invalidate geth's internal read-cache, a matching log must be found in the bloom Filter + // for each of the 32 blocks + tx, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(i + 7)}) + require.NoError(t, err) + require.NotNil(t, tx) + th.Client.Commit() + } - filter1 := logpoller.Filter{"filter1", []common.Hash{ - EmitterABI.Events["Log1"].ID, - EmitterABI.Events["Log2"].ID}, - []common.Address{th.EmitterAddress1}, - 0} - err := th.LogPoller.RegisterFilter(filter1) - require.NoError(t, err) + ctx := testutils.Context(t) - filters, err := th.ORM.LoadFilters(pg.WithParentCtx(testutils.Context(t))) - require.NoError(t, err) - require.Equal(t, 1, len(filters)) - require.Equal(t, filter1, filters["filter1"]) + filter1 := logpoller.Filter{"filter1", []common.Hash{ + EmitterABI.Events["Log1"].ID, + EmitterABI.Events["Log2"].ID}, + []common.Address{th.EmitterAddress1}, + 0} + err := th.LogPoller.RegisterFilter(filter1) + require.NoError(t, err) - err = th.LogPoller.RegisterFilter( - logpoller.Filter{"filter2", - []common.Hash{EmitterABI.Events["Log1"].ID}, - []common.Address{th.EmitterAddress2}, 0}) - require.NoError(t, err) + filters, err := th.ORM.LoadFilters(pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + require.Equal(t, 1, len(filters)) + require.Equal(t, filter1, filters["filter1"]) - defer func() { - assert.NoError(t, th.LogPoller.UnregisterFilter("filter1")) - }() - defer func() { - assert.NoError(t, th.LogPoller.UnregisterFilter("filter2")) - }() + err = th.LogPoller.RegisterFilter( + logpoller.Filter{"filter2", + []common.Hash{EmitterABI.Events["Log1"].ID}, + []common.Address{th.EmitterAddress2}, 0}) + require.NoError(t, err) - // generate some tx's with logs - tx1, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) - require.NoError(t, err) - require.NotNil(t, tx1) + defer func() { + assert.NoError(t, th.LogPoller.UnregisterFilter("filter1")) + }() + defer func() { + assert.NoError(t, th.LogPoller.UnregisterFilter("filter2")) + }() - tx2, err := th.Emitter1.EmitLog2(th.Owner, []*big.Int{big.NewInt(2)}) - require.NoError(t, err) - require.NotNil(t, tx2) + // generate some tx's with logs + tx1, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) + require.NoError(t, err) + require.NotNil(t, tx1) - tx3, err := th.Emitter2.EmitLog1(th.Owner, []*big.Int{big.NewInt(3)}) - require.NoError(t, err) - require.NotNil(t, tx3) + tx2, err := th.Emitter1.EmitLog2(th.Owner, []*big.Int{big.NewInt(2)}) + require.NoError(t, err) + require.NotNil(t, tx2) + + tx3, err := th.Emitter2.EmitLog1(th.Owner, []*big.Int{big.NewInt(3)}) + require.NoError(t, err) + require.NotNil(t, tx3) + + th.Client.Commit() // commit block 34 with 3 tx's included + + h := th.Client.Blockchain().CurrentHeader() // get latest header + require.Equal(t, uint64(34), h.Number.Uint64()) + + // save these 3 receipts for later + receipts := rawdb.ReadReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), uint64(time.Now().Unix()), params.AllEthashProtocolChanges) + require.NotZero(t, receipts.Len()) + + // Simulate a situation where the rpc server has a block, but no logs available for it yet + // this can't happen with geth itself, but can with other clients. + rawdb.WriteReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), types.Receipts{}) // wipes out all logs for block 34 + + body := rawdb.ReadBody(th.EthDB, h.Hash(), h.Number.Uint64()) + require.Equal(t, 3, len(body.Transactions)) + txs := body.Transactions // save transactions for later + body.Transactions = types.Transactions{} // number of tx's must match # of logs for GetLogs() to succeed + rawdb.WriteBody(th.EthDB, h.Hash(), h.Number.Uint64(), body) + + currentBlock := th.PollAndSaveLogs(ctx, 1) + assert.Equal(t, int64(35), currentBlock) + + // simulate logs becoming available + rawdb.WriteReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), receipts) + require.True(t, rawdb.HasReceipts(th.EthDB, h.Hash(), h.Number.Uint64())) + body.Transactions = txs + rawdb.WriteBody(th.EthDB, h.Hash(), h.Number.Uint64(), body) + + // flush out cached block 34 by reading logs from first 32 blocks + query := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(2)), + ToBlock: big.NewInt(int64(33)), + Addresses: []common.Address{th.EmitterAddress1}, + Topics: [][]common.Hash{{EmitterABI.Events["Log1"].ID}}, + } + fLogs, err := th.Client.FilterLogs(ctx, query) + require.NoError(t, err) + require.Equal(t, 32, len(fLogs)) + + // logs shouldn't show up yet + logs, err := th.LogPoller.Logs(34, 34, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + assert.Equal(t, 0, len(logs)) + + th.Client.Commit() + th.Client.Commit() + markBlockAsFinalized(t, th, 34) + + // Run ordinary poller + backup poller at least once + currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) + th.LogPoller.BackupPollAndSaveLogs(ctx, 100) + currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + + require.Equal(t, int64(37), currentBlock+1) + + // logs still shouldn't show up, because we don't want to backfill the last finalized log + // to help with reorg detection + logs, err = th.LogPoller.Logs(34, 34, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + assert.Equal(t, 0, len(logs)) + th.Client.Commit() + markBlockAsFinalized(t, th, 35) - th.Client.Commit() // commit block 34 with 3 tx's included + // Run ordinary poller + backup poller at least once more + th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) + th.LogPoller.BackupPollAndSaveLogs(ctx, 100) + currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - h := th.Client.Blockchain().CurrentHeader() // get latest header - require.Equal(t, uint64(34), h.Number.Uint64()) + require.Equal(t, int64(38), currentBlock+1) - // save these 3 receipts for later - receipts := rawdb.ReadReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), uint64(time.Now().Unix()), params.AllEthashProtocolChanges) - require.NotZero(t, receipts.Len()) + // all 3 logs in block 34 should show up now, thanks to backup logger + logs, err = th.LogPoller.Logs(30, 37, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + assert.Equal(t, 5, len(logs)) + logs, err = th.LogPoller.Logs(34, 34, EmitterABI.Events["Log2"].ID, th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + assert.Equal(t, 1, len(logs)) + logs, err = th.LogPoller.Logs(32, 36, EmitterABI.Events["Log1"].ID, th.EmitterAddress2, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + assert.Equal(t, 1, len(logs)) + }) + } +} - // Simulate a situation where the rpc server has a block, but no logs available for it yet - // this can't happen with geth itself, but can with other clients. - rawdb.WriteReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), types.Receipts{}) // wipes out all logs for block 34 +func TestLogPoller_BackupPollAndSaveLogsWithPollerNotWorking(t *testing.T) { + emittedLogs := 30 + // Intentionally use very low backupLogPollerDelay to verify if finality is used properly + backupLogPollerDelay := int64(0) + ctx := testutils.Context(t) + th := SetupTH(t, true, 0, 3, 2, 1000) + + header, err := th.Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) - body := rawdb.ReadBody(th.EthDB, h.Hash(), h.Number.Uint64()) - require.Equal(t, 3, len(body.Transactions)) - txs := body.Transactions // save transactions for later - body.Transactions = types.Transactions{} // number of tx's must match # of logs for GetLogs() to succeed - rawdb.WriteBody(th.EthDB, h.Hash(), h.Number.Uint64(), body) + // Emit some logs in blocks + for i := 0; i < emittedLogs; i++ { + _, err2 := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err2) + th.Client.Commit() + } + // First PollAndSave, no filters are registered + // 0 (finalized) -> 1 -> 2 -> ... currentBlock := th.PollAndSaveLogs(ctx, 1) - assert.Equal(t, int64(35), currentBlock) + // currentBlock should be blockChain start + number of emitted logs + 1 + assert.Equal(t, int64(emittedLogs)+header.Number.Int64()+1, currentBlock) - // simulate logs becoming available - rawdb.WriteReceipts(th.EthDB, h.Hash(), h.Number.Uint64(), receipts) - require.True(t, rawdb.HasReceipts(th.EthDB, h.Hash(), h.Number.Uint64())) - body.Transactions = txs - rawdb.WriteBody(th.EthDB, h.Hash(), h.Number.Uint64(), body) + // LogPoller not working, but chain in the meantime has progressed + // 0 -> 1 -> 2 -> ... -> currentBlock - 10 (finalized) -> .. -> currentBlock + markBlockAsFinalized(t, th, currentBlock-10) - // flush out cached block 34 by reading logs from first 32 blocks - query := ethereum.FilterQuery{ - FromBlock: big.NewInt(int64(2)), - ToBlock: big.NewInt(int64(33)), + err = th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, Addresses: []common.Address{th.EmitterAddress1}, - Topics: [][]common.Hash{{EmitterABI.Events["Log1"].ID}}, - } - fLogs, err := th.Client.FilterLogs(ctx, query) + }) require.NoError(t, err) - require.Equal(t, 32, len(fLogs)) - // logs shouldn't show up yet - logs, err := th.LogPoller.Logs(34, 34, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, - pg.WithParentCtx(testutils.Context(t))) + // LogPoller should backfill starting from the last finalized block stored in db (genesis block) + // till the latest finalized block reported by chain. + th.LogPoller.BackupPollAndSaveLogs(ctx, backupLogPollerDelay) + require.NoError(t, err) + + logs, err := th.LogPoller.Logs( + 0, + currentBlock, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) require.NoError(t, err) - assert.Equal(t, 0, len(logs)) + require.Len(t, logs, emittedLogs-10) + // Progressing even more, move blockchain forward by 1 block and mark it as finalized th.Client.Commit() + markBlockAsFinalized(t, th, currentBlock) + th.LogPoller.BackupPollAndSaveLogs(ctx, backupLogPollerDelay) + + // All emitted logs should be backfilled + logs, err = th.LogPoller.Logs( + 0, + currentBlock+1, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) +} + +func TestLogPoller_BackupPollAndSaveLogsWithDeepBlockDelay(t *testing.T) { + emittedLogs := 30 + ctx := testutils.Context(t) + th := SetupTH(t, true, 0, 3, 2, 1000) + + // Emit some logs in blocks + for i := 0; i < emittedLogs; i++ { + _, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + // Emit one more empty block th.Client.Commit() - // Run ordinary poller + backup poller at least once - currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) - th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) - th.LogPoller.BackupPollAndSaveLogs(ctx, 100) - currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + header, err := th.Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) + // Mark everything as finalized + markBlockAsFinalized(t, th, header.Number.Int64()) - require.Equal(t, int64(37), currentBlock+1) + // First PollAndSave, no filters are registered, but finalization is the same as the latest block + // 1 -> 2 -> ... + th.PollAndSaveLogs(ctx, 1) - // logs still shouldn't show up, because we don't want to backfill the last finalized log - // to help with reorg detection - logs, err = th.LogPoller.Logs(34, 34, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, - pg.WithParentCtx(testutils.Context(t))) + // Register filter + err = th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) require.NoError(t, err) - assert.Equal(t, 0, len(logs)) - th.Client.Commit() + // Should fallback to the backupPollerBlockDelay when finalization was very high in a previous PollAndSave + th.LogPoller.BackupPollAndSaveLogs(ctx, int64(emittedLogs)) + require.NoError(t, err) + + // All emitted logs should be backfilled + logs, err := th.LogPoller.Logs( + 0, + header.Number.Int64()+1, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) +} + +func TestLogPoller_BackupPollAndSaveLogsSkippingLogsThatAreTooOld(t *testing.T) { + logsBatch := 10 + // Intentionally use very low backupLogPollerDelay to verify if finality is used properly + ctx := testutils.Context(t) + th := SetupTH(t, true, 0, 3, 2, 1000) - // Run ordinary poller + backup poller at least once more - th.LogPoller.PollAndSaveLogs(ctx, currentBlock+1) - th.LogPoller.BackupPollAndSaveLogs(ctx, 100) - currentBlock, _ = th.LogPoller.LatestBlock(pg.WithParentCtx(testutils.Context(t))) + //header, err := th.Client.HeaderByNumber(ctx, nil) + //require.NoError(t, err) - require.Equal(t, int64(38), currentBlock+1) + // Emit some logs in blocks + for i := 1; i <= logsBatch; i++ { + _, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } - // all 3 logs in block 34 should show up now, thanks to backup logger - logs, err = th.LogPoller.Logs(30, 37, EmitterABI.Events["Log1"].ID, th.EmitterAddress1, - pg.WithParentCtx(testutils.Context(t))) + // First PollAndSave, no filters are registered, but finalization is the same as the latest block + // 1 -> 2 -> ... -> firstBatchBlock + firstBatchBlock := th.PollAndSaveLogs(ctx, 1) + // Mark current tip of the chain as finalized (after emitting 10 logs) + markBlockAsFinalized(t, th, firstBatchBlock) + + // Emit 2nd batch of block + for i := 1; i <= logsBatch; i++ { + _, err := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(100 + i))}) + require.NoError(t, err) + th.Client.Commit() + } + + // 1 -> 2 -> ... -> firstBatchBlock (finalized) -> .. -> firstBatchBlock + emitted logs + secondBatchBlock := th.PollAndSaveLogs(ctx, firstBatchBlock) + // Mark current tip of the block as finalized (after emitting 20 logs) + markBlockAsFinalized(t, th, secondBatchBlock) + + // Register filter + err := th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) require.NoError(t, err) - assert.Equal(t, 5, len(logs)) - logs, err = th.LogPoller.Logs(34, 34, EmitterABI.Events["Log2"].ID, th.EmitterAddress1, - pg.WithParentCtx(testutils.Context(t))) + + // Should pick logs starting from one block behind the latest finalized block + th.LogPoller.BackupPollAndSaveLogs(ctx, 0) require.NoError(t, err) - assert.Equal(t, 1, len(logs)) - logs, err = th.LogPoller.Logs(32, 36, EmitterABI.Events["Log1"].ID, th.EmitterAddress2, - pg.WithParentCtx(testutils.Context(t))) + + // Only the 2nd batch + 1 log from a previous batch should be backfilled, because we perform backfill starting + // from one block behind the latest finalized block + logs, err := th.LogPoller.Logs( + 0, + secondBatchBlock, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) require.NoError(t, err) - assert.Equal(t, 1, len(logs)) + require.Len(t, logs, logsBatch+1) + require.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000009`), logs[0].Data) } func TestLogPoller_BlockTimestamps(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) addresses := []common.Address{th.EmitterAddress1, th.EmitterAddress2} topics := []common.Hash{EmitterABI.Events["Log1"].ID, EmitterABI.Events["Log2"].ID} @@ -437,7 +663,7 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { }, 10e6) _, _, emitter1, err := log_emitter.DeployLogEmitter(owner, ec) require.NoError(t, err) - lp := logpoller.NewLogPoller(orm, client.NewSimulatedBackendClient(t, ec, chainID), lggr, 15*time.Second, int64(finalityDepth), 3, 2, 1000) + lp := logpoller.NewLogPoller(orm, client.NewSimulatedBackendClient(t, ec, chainID), lggr, 15*time.Second, false, int64(finalityDepth), 3, 2, 1000) for i := 0; i < finalityDepth; i++ { // Have enough blocks that we could reorg the full finalityDepth-1. ec.Commit() } @@ -504,223 +730,335 @@ func TestLogPoller_SynchronizedWithGeth(t *testing.T) { func TestLogPoller_PollAndSaveLogs(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) - // Set up a log poller listening for log emitter logs. - err := th.LogPoller.RegisterFilter(logpoller.Filter{ - "Test Emitter 1 & 2", []common.Hash{EmitterABI.Events["Log1"].ID, EmitterABI.Events["Log2"].ID}, - []common.Address{th.EmitterAddress1, th.EmitterAddress2}, 0, - }) - require.NoError(t, err) + tests := []struct { + name string + finalityDepth int64 + finalityTag bool + }{ + { + name: "fixed finality depth without finality tag", + finalityDepth: 3, + finalityTag: false, + }, + { + name: "chain finality in use", + finalityDepth: 0, + finalityTag: true, + }, + } - b, err := th.Client.BlockByNumber(testutils.Context(t), nil) - require.NoError(t, err) - require.Equal(t, uint64(1), b.NumberU64()) - require.Equal(t, uint64(10), b.Time()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, tt.finalityTag, tt.finalityDepth, 3, 2, 1000) - // Test scenario: single block in chain, no logs. - // Chain genesis <- 1 - // DB: empty - newStart := th.PollAndSaveLogs(testutils.Context(t), 1) - assert.Equal(t, int64(2), newStart) + // Set up a log poller listening for log emitter logs. + err := th.LogPoller.RegisterFilter(logpoller.Filter{ + "Test Emitter 1 & 2", []common.Hash{EmitterABI.Events["Log1"].ID, EmitterABI.Events["Log2"].ID}, + []common.Address{th.EmitterAddress1, th.EmitterAddress2}, 0, + }) + require.NoError(t, err) - // We expect to have saved block 1. - lpb, err := th.ORM.SelectBlockByNumber(1) - require.NoError(t, err) - assert.Equal(t, lpb.BlockHash, b.Hash()) - assert.Equal(t, lpb.BlockNumber, int64(b.NumberU64())) - assert.Equal(t, int64(1), int64(b.NumberU64())) - assert.Equal(t, uint64(10), b.Time()) + b, err := th.Client.BlockByNumber(testutils.Context(t), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), b.NumberU64()) + require.Equal(t, uint64(10), b.Time()) - // No logs. - lgs, err := th.ORM.SelectLogsByBlockRange(1, 1) - require.NoError(t, err) - assert.Equal(t, 0, len(lgs)) - th.assertHaveCanonical(t, 1, 1) + // Test scenario: single block in chain, no logs. + // Chain genesis <- 1 + // DB: empty + newStart := th.PollAndSaveLogs(testutils.Context(t), 1) + assert.Equal(t, int64(2), newStart) - // Polling again should be a noop, since we are at the latest. - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(2), newStart) - latest, err := th.ORM.SelectLatestBlock() - require.NoError(t, err) - assert.Equal(t, int64(1), latest.BlockNumber) - th.assertHaveCanonical(t, 1, 1) + // We expect to have saved block 1. + lpb, err := th.ORM.SelectBlockByNumber(1) + require.NoError(t, err) + assert.Equal(t, lpb.BlockHash, b.Hash()) + assert.Equal(t, lpb.BlockNumber, int64(b.NumberU64())) + assert.Equal(t, int64(1), int64(b.NumberU64())) + assert.Equal(t, uint64(10), b.Time()) - // Test scenario: one log 2 block chain. - // Chain gen <- 1 <- 2 (L1) - // DB: 1 - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) - require.NoError(t, err) - th.Client.Commit() + // No logs. + lgs, err := th.ORM.SelectLogsByBlockRange(1, 1) + require.NoError(t, err) + assert.Equal(t, 0, len(lgs)) + th.assertHaveCanonical(t, 1, 1) - // Polling should get us the L1 log. - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(3), newStart) - latest, err = th.ORM.SelectLatestBlock() - require.NoError(t, err) - assert.Equal(t, int64(2), latest.BlockNumber) - lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) - require.NoError(t, err) - require.Equal(t, 1, len(lgs)) - assert.Equal(t, th.EmitterAddress1, lgs[0].Address) - assert.Equal(t, latest.BlockHash, lgs[0].BlockHash) - assert.Equal(t, latest.BlockTimestamp, lgs[0].BlockTimestamp) - assert.Equal(t, hexutil.Encode(lgs[0].Topics[0]), EmitterABI.Events["Log1"].ID.String()) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000001`), - lgs[0].Data) - - // Test scenario: single block reorg with log. - // Chain gen <- 1 <- 2 (L1_1) - // \ 2'(L1_2) <- 3 - // DB: 1, 2 - // - Detect a reorg, - // - Update the block 2's hash - // - Save L1' - // - L1_1 deleted - reorgedOutBlock, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(2)) - require.NoError(t, err) - lca, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(1)) - require.NoError(t, err) - require.NoError(t, th.Client.Fork(testutils.Context(t), lca.Hash())) - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(2)}) - require.NoError(t, err) - // Create 2' - th.Client.Commit() - // Create 3 (we need a new block for us to do any polling and detect the reorg). - th.Client.Commit() + // Polling again should be a noop, since we are at the latest. + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(2), newStart) + latest, err := th.ORM.SelectLatestBlock() + require.NoError(t, err) + assert.Equal(t, int64(1), latest.BlockNumber) + th.assertHaveCanonical(t, 1, 1) - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(4), newStart) - latest, err = th.ORM.SelectLatestBlock() - require.NoError(t, err) - assert.Equal(t, int64(3), latest.BlockNumber) - lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) - require.NoError(t, err) - require.Equal(t, 1, len(lgs)) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data) - th.assertHaveCanonical(t, 1, 3) - - // Test scenario: reorg back to previous tip. - // Chain gen <- 1 <- 2 (L1_1) <- 3' (L1_3) <- 4 - // \ 2'(L1_2) <- 3 - require.NoError(t, th.Client.Fork(testutils.Context(t), reorgedOutBlock.Hash())) - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(3)}) - require.NoError(t, err) - // Create 3' - th.Client.Commit() - // Create 4 - th.Client.Commit() - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(5), newStart) - latest, err = th.ORM.SelectLatestBlock() - require.NoError(t, err) - assert.Equal(t, int64(4), latest.BlockNumber) - lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) - require.NoError(t, err) - // We expect ONLY L1_1 and L1_3 since L1_2 is reorg'd out. - assert.Equal(t, 2, len(lgs)) - assert.Equal(t, int64(2), lgs[0].BlockNumber) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000001`), lgs[0].Data) - assert.Equal(t, int64(3), lgs[1].BlockNumber) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000003`), lgs[1].Data) - th.assertHaveCanonical(t, 1, 1) - th.assertHaveCanonical(t, 3, 4) - th.assertDontHave(t, 2, 2) // 2 gets backfilled - - // Test scenario: multiple logs per block for many blocks (also after reorg). - // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) - // \ 2'(L1_2) <- 3 - // DB: 1, 2', 3' - // - Should save 4, 5, 6 blocks - // - Should obtain logs L1_3, L2_5, L1_6 - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(4)}) - require.NoError(t, err) - _, err = th.Emitter2.EmitLog1(th.Owner, []*big.Int{big.NewInt(5)}) - require.NoError(t, err) - // Create 4 - th.Client.Commit() - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(6)}) - require.NoError(t, err) - // Create 5 - th.Client.Commit() + // Test scenario: one log 2 block chain. + // Chain gen <- 1 <- 2 (L1) + // DB: 1 + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) + require.NoError(t, err) + th.Client.Commit() - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(7), newStart) - lgs, err = th.ORM.SelectLogsByBlockRange(4, 6) - require.NoError(t, err) - require.Equal(t, 3, len(lgs)) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000004`), lgs[0].Data) - assert.Equal(t, th.EmitterAddress1, lgs[0].Address) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000005`), lgs[1].Data) - assert.Equal(t, th.EmitterAddress2, lgs[1].Address) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000006`), lgs[2].Data) - assert.Equal(t, th.EmitterAddress1, lgs[2].Address) - th.assertHaveCanonical(t, 1, 1) - th.assertDontHave(t, 2, 2) // 2 gets backfilled - th.assertHaveCanonical(t, 3, 6) - - // Test scenario: node down for exactly finality + 2 blocks - // Note we only backfill up to finalized - 1 blocks, because we need to save the - // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) <- 7 (L1_7) <- 8 (L1_8) <- 9 (L1_9) <- 10 (L1_10) - // \ 2'(L1_2) <- 3 - // DB: 1, 2, 3, 4, 5, 6 - // - We expect block 7 to backfilled (treated as finalized) - // - Then block 8-10 to be handled block by block (treated as unfinalized). - for i := 7; i < 11; i++ { - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) - require.NoError(t, err) - th.Client.Commit() + // Polling should get us the L1 log. + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(3), newStart) + latest, err = th.ORM.SelectLatestBlock() + require.NoError(t, err) + assert.Equal(t, int64(2), latest.BlockNumber) + lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + assert.Equal(t, th.EmitterAddress1, lgs[0].Address) + assert.Equal(t, latest.BlockHash, lgs[0].BlockHash) + assert.Equal(t, latest.BlockTimestamp, lgs[0].BlockTimestamp) + assert.Equal(t, hexutil.Encode(lgs[0].Topics[0]), EmitterABI.Events["Log1"].ID.String()) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000001`), + lgs[0].Data) + + // Test scenario: single block reorg with log. + // Chain gen <- 1 <- 2 (L1_1) + // \ 2'(L1_2) <- 3 + // DB: 1, 2 + // - Detect a reorg, + // - Update the block 2's hash + // - Save L1' + // - L1_1 deleted + reorgedOutBlock, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(2)) + require.NoError(t, err) + lca, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(1)) + require.NoError(t, err) + require.NoError(t, th.Client.Fork(testutils.Context(t), lca.Hash())) + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(2)}) + require.NoError(t, err) + // Create 2' + th.Client.Commit() + // Create 3 (we need a new block for us to do any polling and detect the reorg). + th.Client.Commit() + + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(4), newStart) + latest, err = th.ORM.SelectLatestBlock() + require.NoError(t, err) + assert.Equal(t, int64(3), latest.BlockNumber) + lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) + require.NoError(t, err) + require.Equal(t, 1, len(lgs)) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data) + th.assertHaveCanonical(t, 1, 3) + + // Test scenario: reorg back to previous tip. + // Chain gen <- 1 <- 2 (L1_1) <- 3' (L1_3) <- 4 + // \ 2'(L1_2) <- 3 + require.NoError(t, th.Client.Fork(testutils.Context(t), reorgedOutBlock.Hash())) + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(3)}) + require.NoError(t, err) + // Create 3' + th.Client.Commit() + // Create 4 + th.Client.Commit() + // Mark block 1 as finalized + markBlockAsFinalized(t, th, 1) + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(5), newStart) + latest, err = th.ORM.SelectLatestBlock() + require.NoError(t, err) + assert.Equal(t, int64(4), latest.BlockNumber) + lgs, err = th.ORM.SelectLogsByBlockRange(1, 3) + require.NoError(t, err) + // We expect ONLY L1_1 and L1_3 since L1_2 is reorg'd out. + assert.Equal(t, 2, len(lgs)) + assert.Equal(t, int64(2), lgs[0].BlockNumber) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000001`), lgs[0].Data) + assert.Equal(t, int64(3), lgs[1].BlockNumber) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000003`), lgs[1].Data) + th.assertHaveCanonical(t, 1, 1) + th.assertHaveCanonical(t, 3, 4) + th.assertDontHave(t, 2, 2) // 2 gets backfilled + + // Test scenario: multiple logs per block for many blocks (also after reorg). + // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) + // \ 2'(L1_2) <- 3 + // DB: 1, 2', 3' + // - Should save 4, 5, 6 blocks + // - Should obtain logs L1_3, L2_5, L1_6 + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(4)}) + require.NoError(t, err) + _, err = th.Emitter2.EmitLog1(th.Owner, []*big.Int{big.NewInt(5)}) + require.NoError(t, err) + // Create 4 + th.Client.Commit() + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(6)}) + require.NoError(t, err) + // Create 5 + th.Client.Commit() + // Mark block 2 as finalized + markBlockAsFinalized(t, th, 3) + + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(7), newStart) + lgs, err = th.ORM.SelectLogsByBlockRange(4, 6) + require.NoError(t, err) + require.Equal(t, 3, len(lgs)) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000004`), lgs[0].Data) + assert.Equal(t, th.EmitterAddress1, lgs[0].Address) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000005`), lgs[1].Data) + assert.Equal(t, th.EmitterAddress2, lgs[1].Address) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000006`), lgs[2].Data) + assert.Equal(t, th.EmitterAddress1, lgs[2].Address) + th.assertHaveCanonical(t, 1, 1) + th.assertDontHave(t, 2, 2) // 2 gets backfilled + th.assertHaveCanonical(t, 3, 6) + + // Test scenario: node down for exactly finality + 2 blocks + // Note we only backfill up to finalized - 1 blocks, because we need to save the + // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) <- 7 (L1_7) <- 8 (L1_8) <- 9 (L1_9) <- 10 (L1_10) + // \ 2'(L1_2) <- 3 + // DB: 1, 2, 3, 4, 5, 6 + // - We expect block 7 to backfilled (treated as finalized) + // - Then block 8-10 to be handled block by block (treated as unfinalized). + for i := 7; i < 11; i++ { + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + // Mark block 7 as finalized + markBlockAsFinalized(t, th, 7) + + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(11), newStart) + lgs, err = th.ORM.SelectLogsByBlockRange(7, 9) + require.NoError(t, err) + require.Equal(t, 3, len(lgs)) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000007`), lgs[0].Data) + assert.Equal(t, int64(7), lgs[0].BlockNumber) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000008`), lgs[1].Data) + assert.Equal(t, int64(8), lgs[1].BlockNumber) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000009`), lgs[2].Data) + assert.Equal(t, int64(9), lgs[2].BlockNumber) + th.assertDontHave(t, 7, 7) // Do not expect to save backfilled blocks. + th.assertHaveCanonical(t, 8, 10) + + // Test scenario large backfill (multiple batches) + // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) <- 7 (L1_7) <- 8 (L1_8) <- 9 (L1_9) <- 10..16 + // \ 2'(L1_2) <- 3 + // DB: 1, 2, 3, 4, 5, 6, (backfilled 7), 8, 9, 10 + // - 11, 12, 13 backfilled in batch 1 + // - 14 backfilled in batch 2 + // - 15, 16, 17 to be treated as unfinalized + for i := 11; i < 18; i++ { + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + // Mark block 14 as finalized + markBlockAsFinalized(t, th, 14) + + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(18), newStart) + lgs, err = th.ORM.SelectLogsByBlockRange(11, 17) + require.NoError(t, err) + assert.Equal(t, 7, len(lgs)) + th.assertHaveCanonical(t, 15, 16) + th.assertDontHave(t, 11, 14) // Do not expect to save backfilled blocks. + + // Verify that a custom block timestamp will get written to db correctly also + b, err = th.Client.BlockByNumber(testutils.Context(t), nil) + require.NoError(t, err) + require.Equal(t, uint64(17), b.NumberU64()) + require.Equal(t, uint64(170), b.Time()) + require.NoError(t, th.Client.AdjustTime(1*time.Hour)) + th.Client.Commit() + + b, err = th.Client.BlockByNumber(testutils.Context(t), nil) + require.NoError(t, err) + require.Equal(t, uint64(180+time.Hour.Seconds()), b.Time()) + }) } - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(11), newStart) - lgs, err = th.ORM.SelectLogsByBlockRange(7, 9) - require.NoError(t, err) - require.Equal(t, 3, len(lgs)) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000007`), lgs[0].Data) - assert.Equal(t, int64(7), lgs[0].BlockNumber) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000008`), lgs[1].Data) - assert.Equal(t, int64(8), lgs[1].BlockNumber) - assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000009`), lgs[2].Data) - assert.Equal(t, int64(9), lgs[2].BlockNumber) - th.assertDontHave(t, 7, 7) // Do not expect to save backfilled blocks. - th.assertHaveCanonical(t, 8, 10) - - // Test scenario large backfill (multiple batches) - // Chain gen <- 1 <- 2 (L1_1) <- 3' L1_3 <- 4 <- 5 (L1_4, L2_5) <- 6 (L1_6) <- 7 (L1_7) <- 8 (L1_8) <- 9 (L1_9) <- 10..16 - // \ 2'(L1_2) <- 3 - // DB: 1, 2, 3, 4, 5, 6, (backfilled 7), 8, 9, 10 - // - 11, 12, 13 backfilled in batch 1 - // - 14 backfilled in batch 2 - // - 15, 16, 17 to be treated as unfinalized - for i := 11; i < 18; i++ { - _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) - require.NoError(t, err) - th.Client.Commit() +} + +func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + finalityDepth int64 + finalityTag bool + }{ + { + name: "fixed finality depth without finality tag", + finalityDepth: 3, + finalityTag: false, + }, + { + name: "chain finality in use", + finalityDepth: 0, + finalityTag: true, + }, } - newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) - assert.Equal(t, int64(18), newStart) - lgs, err = th.ORM.SelectLogsByBlockRange(11, 17) - require.NoError(t, err) - assert.Equal(t, 7, len(lgs)) - th.assertHaveCanonical(t, 15, 16) - th.assertDontHave(t, 11, 14) // Do not expect to save backfilled blocks. - // Verify that a custom block timestamp will get written to db correctly also - b, err = th.Client.BlockByNumber(testutils.Context(t), nil) - require.NoError(t, err) - require.Equal(t, uint64(17), b.NumberU64()) - require.Equal(t, uint64(170), b.Time()) - require.NoError(t, th.Client.AdjustTime(1*time.Hour)) - th.Client.Commit() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, tt.finalityTag, tt.finalityDepth, 3, 2, 1000) - b, err = th.Client.BlockByNumber(testutils.Context(t), nil) - require.NoError(t, err) - require.Equal(t, uint64(180+time.Hour.Seconds()), b.Time()) + // Set up a log poller listening for log emitter logs. + err := th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) + require.NoError(t, err) + + // Test scenario: one log 2 block chain. + // Chain gen <- 1 <- 2 (L1_1) + // DB: 1 + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(1)}) + require.NoError(t, err) + th.Client.Commit() + markBlockAsFinalized(t, th, 1) + + // Polling should get us the L1 log. + newStart := th.PollAndSaveLogs(testutils.Context(t), 1) + assert.Equal(t, int64(3), newStart) + // Check that L1_1 has a proper data payload + lgs, err := th.ORM.SelectLogsByBlockRange(2, 2) + require.NoError(t, err) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000001`), lgs[0].Data) + + // Single block reorg and log poller not working for a while, mine blocks and progress with finalization + // Chain gen <- 1 <- 2 (L1_1) + // \ 2'(L1_2) <- 3 <- 4 <- 5 <- 6 (finalized on chain) <- 7 <- 8 <- 9 <- 10 + lca, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(1)) + require.NoError(t, err) + require.NoError(t, th.Client.Fork(testutils.Context(t), lca.Hash())) + // Create 2' + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(2)}) + require.NoError(t, err) + th.Client.Commit() + // Create 3-10 + for i := 3; i < 10; i++ { + _, err = th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err) + th.Client.Commit() + } + markBlockAsFinalized(t, th, 6) + + newStart = th.PollAndSaveLogs(testutils.Context(t), newStart) + assert.Equal(t, int64(10), newStart) + + // Expect L1_2 to be properly updated + lgs, err = th.ORM.SelectLogsByBlockRange(2, 2) + require.NoError(t, err) + assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data) + th.assertHaveCanonical(t, 1, 1) + th.assertDontHave(t, 2, 5) // These blocks are backfilled + th.assertHaveCanonical(t, 6, 10) + }) + } } func TestLogPoller_LoadFilters(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) filter1 := logpoller.Filter{"first Filter", []common.Hash{ EmitterABI.Events["Log1"].ID, EmitterABI.Events["Log2"].ID}, []common.Address{th.EmitterAddress1, th.EmitterAddress2}, 0} @@ -771,7 +1109,7 @@ func TestLogPoller_LoadFilters(t *testing.T) { func TestLogPoller_GetBlocks_Range(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) err := th.LogPoller.RegisterFilter(logpoller.Filter{"GetBlocks Test", []common.Hash{ EmitterABI.Events["Log1"].ID, EmitterABI.Events["Log2"].ID}, []common.Address{th.EmitterAddress1, th.EmitterAddress2}, 0}, @@ -881,7 +1219,7 @@ func TestLogPoller_GetBlocks_Range(t *testing.T) { func TestGetReplayFromBlock(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) // Commit a few blocks for i := 0; i < 10; i++ { th.Client.Commit() @@ -942,7 +1280,7 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { ec.Commit() ec.Commit() - lp := logpoller.NewLogPoller(o, client.NewSimulatedBackendClient(t, ec, chainID2), lggr, 1*time.Hour, 2, 3, 2, 1000) + lp := logpoller.NewLogPoller(o, client.NewSimulatedBackendClient(t, ec, chainID2), lggr, 1*time.Hour, false, 2, 3, 2, 1000) err = lp.Replay(ctx, 5) // block number too high require.ErrorContains(t, err, "Invalid replay block number") @@ -1045,7 +1383,7 @@ func TestTooManyLogResults(t *testing.T) { chainID := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) o := logpoller.NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) - lp := logpoller.NewLogPoller(o, ec, lggr, 1*time.Hour, 2, 20, 10, 1000) + lp := logpoller.NewLogPoller(o, ec, lggr, 1*time.Hour, false, 2, 20, 10, 1000) expected := []int64{10, 5, 2, 1} clientErr := client.JsonError{ @@ -1121,3 +1459,259 @@ func TestTooManyLogResults(t *testing.T) { require.Len(t, crit, 1) assert.Contains(t, crit[0].Message, "Too many log results in a single block") } + +func Test_PollAndQueryFinalizedBlocks(t *testing.T) { + t.Parallel() + ctx := testutils.Context(t) + firstBatchLen := 3 + secondBatchLen := 5 + + th := SetupTH(t, true, 2, 3, 2, 1000) + + eventSig := EmitterABI.Events["Log1"].ID + err := th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "GetBlocks Test", + EventSigs: []common.Hash{eventSig}, + Addresses: []common.Address{th.EmitterAddress1}}, + ) + require.NoError(t, err) + + // Generate block that will be finalized + for i := 0; i < firstBatchLen; i++ { + _, err1 := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Mark current head as finalized + h := th.Client.Blockchain().CurrentHeader() + th.Client.Blockchain().SetFinalized(h) + + // Generate next blocks, not marked as finalized + for i := 0; i < secondBatchLen; i++ { + _, err1 := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + currentBlock := th.PollAndSaveLogs(ctx, 1) + require.Equal(t, int(currentBlock), firstBatchLen+secondBatchLen+2) + + finalizedLogs, err := th.LogPoller.LogsDataWordGreaterThan( + eventSig, + th.EmitterAddress1, + 0, + common.Hash{}, + logpoller.Finalized, + ) + require.NoError(t, err) + require.Len(t, finalizedLogs, firstBatchLen) + + numberOfConfirmations := 1 + logsByConfs, err := th.LogPoller.LogsDataWordGreaterThan( + eventSig, + th.EmitterAddress1, + 0, + common.Hash{}, + logpoller.Confirmations(numberOfConfirmations), + ) + require.NoError(t, err) + require.Len(t, logsByConfs, firstBatchLen+secondBatchLen-numberOfConfirmations) +} + +func Test_PollAndSavePersistsFinalityInBlocks(t *testing.T) { + ctx := testutils.Context(t) + numberOfBlocks := 10 + + tests := []struct { + name string + useFinalityTag bool + finalityDepth int64 + expectedFinalizedBlock int64 + }{ + { + name: "using fixed finality depth", + useFinalityTag: false, + finalityDepth: 2, + expectedFinalizedBlock: int64(numberOfBlocks - 2), + }, + { + name: "setting last finalized block number to 0 if finality is too deep", + useFinalityTag: false, + finalityDepth: 20, + expectedFinalizedBlock: 0, + }, + { + name: "using finality from chain", + useFinalityTag: true, + finalityDepth: 0, + expectedFinalizedBlock: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, tt.useFinalityTag, tt.finalityDepth, 3, 2, 1000) + // Mark first block as finalized + h := th.Client.Blockchain().CurrentHeader() + th.Client.Blockchain().SetFinalized(h) + + // Create a couple of blocks + for i := 0; i < numberOfBlocks-1; i++ { + th.Client.Commit() + } + + th.PollAndSaveLogs(ctx, 1) + + latestBlock, err := th.ORM.SelectLatestBlock() + require.NoError(t, err) + require.Equal(t, int64(numberOfBlocks), latestBlock.BlockNumber) + require.Equal(t, tt.expectedFinalizedBlock, latestBlock.FinalizedBlockNumber) + }) + } +} + +func Test_CreatedAfterQueriesWithBackfill(t *testing.T) { + emittedLogs := 60 + ctx := testutils.Context(t) + + tests := []struct { + name string + finalityDepth int64 + finalityTag bool + }{ + { + name: "fixed finality depth without finality tag", + finalityDepth: 10, + finalityTag: false, + }, + { + name: "chain finality in use", + finalityDepth: 0, + finalityTag: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, tt.finalityTag, tt.finalityDepth, 3, 2, 1000) + + header, err := th.Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) + + genesisBlockTime := time.UnixMilli(int64(header.Time)) + + // Emit some logs in blocks + for i := 0; i < emittedLogs; i++ { + _, err2 := th.Emitter1.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err2) + th.Client.Commit() + } + + // First PollAndSave, no filters are registered + currentBlock := th.PollAndSaveLogs(ctx, 1) + + err = th.LogPoller.RegisterFilter(logpoller.Filter{ + Name: "Test Emitter", + EventSigs: []common.Hash{EmitterABI.Events["Log1"].ID}, + Addresses: []common.Address{th.EmitterAddress1}, + }) + require.NoError(t, err) + + // Emit blocks to cover finality depth, because backup always backfill up to the one block before last finalized + for i := 0; i < int(tt.finalityDepth)+1; i++ { + bh := th.Client.Commit() + markBlockAsFinalizedByHash(t, th, bh) + } + + // LogPoller should backfill entire history + th.LogPoller.BackupPollAndSaveLogs(ctx, 100) + require.NoError(t, err) + + // Make sure that all logs are backfilled + logs, err := th.LogPoller.Logs( + 0, + currentBlock, + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) + + // We should get all the logs by the block_timestamp + logs, err = th.LogPoller.LogsCreatedAfter( + EmitterABI.Events["Log1"].ID, + th.EmitterAddress1, + genesisBlockTime, + 0, + pg.WithParentCtx(testutils.Context(t)), + ) + require.NoError(t, err) + require.Len(t, logs, emittedLogs) + }) + } +} + +func Test_PruneOldBlocks(t *testing.T) { + ctx := testutils.Context(t) + + tests := []struct { + name string + keepFinalizedBlocksDepth int64 + blockToCreate int + blocksLeft int + wantErr bool + }{ + { + name: "returns error if no blocks yet", + keepFinalizedBlocksDepth: 10, + blockToCreate: 0, + wantErr: true, + }, + { + name: "returns if there is not enough blocks in the db", + keepFinalizedBlocksDepth: 11, + blockToCreate: 10, + blocksLeft: 10, + }, + { + name: "prunes matching blocks", + keepFinalizedBlocksDepth: 1000, + blockToCreate: 2000, + blocksLeft: 1010, // last finalized block is 10 block behind + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + th := SetupTH(t, true, 0, 3, 2, tt.keepFinalizedBlocksDepth) + + for i := 1; i <= tt.blockToCreate; i++ { + err := th.ORM.InsertBlock(utils.RandomBytes32(), int64(i+10), time.Now(), int64(i)) + require.NoError(t, err) + } + + if tt.wantErr { + require.Error(t, th.LogPoller.PruneOldBlocks(ctx)) + return + } + + require.NoError(t, th.LogPoller.PruneOldBlocks(ctx)) + blocks, err := th.ORM.GetBlocksRange(0, math.MaxInt64, pg.WithParentCtx(ctx)) + require.NoError(t, err) + assert.Len(t, blocks, tt.blocksLeft) + }) + } +} + +func markBlockAsFinalized(t *testing.T, th TestHarness, blockNumber int64) { + b, err := th.Client.BlockByNumber(testutils.Context(t), big.NewInt(blockNumber)) + require.NoError(t, err) + th.Client.Blockchain().SetFinalized(b.Header()) +} + +func markBlockAsFinalizedByHash(t *testing.T, th TestHarness, blockHash common.Hash) { + b, err := th.Client.BlockByHash(testutils.Context(t), blockHash) + require.NoError(t, err) + th.Client.Blockchain().SetFinalized(b.Header()) +} diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 39d37f31a32..f4357341646 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -99,7 +99,7 @@ func (_m *LogPoller) HealthReport() map[string]error { } // IndexedLogs provides a mock function with given fields: eventSig, address, topicIndex, topicValues, confs, qopts -func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -111,10 +111,10 @@ func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, t var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, topicIndex, topicValues, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, topicIndex, topicValues, confs, qopts...) } else { if ret.Get(0) != nil { @@ -122,7 +122,7 @@ func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, t } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, []common.Hash, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, []common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, topicIndex, topicValues, confs, qopts...) } else { r1 = ret.Error(1) @@ -198,7 +198,7 @@ func (_m *LogPoller) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Has } // IndexedLogsCreatedAfter provides a mock function with given fields: eventSig, address, topicIndex, topicValues, after, confs, qopts -func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -210,10 +210,10 @@ func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, topicIndex, topicValues, after, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, topicIndex, topicValues, after, confs, qopts...) } else { if ret.Get(0) != nil { @@ -221,7 +221,7 @@ func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, []common.Hash, time.Time, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, []common.Hash, time.Time, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, topicIndex, topicValues, after, confs, qopts...) } else { r1 = ret.Error(1) @@ -231,7 +231,7 @@ func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo } // IndexedLogsTopicGreaterThan provides a mock function with given fields: eventSig, address, topicIndex, topicValueMin, confs, qopts -func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -243,10 +243,10 @@ func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address c var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, topicIndex, topicValueMin, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, topicIndex, topicValueMin, confs, qopts...) } else { if ret.Get(0) != nil { @@ -254,7 +254,7 @@ func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address c } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, topicIndex, topicValueMin, confs, qopts...) } else { r1 = ret.Error(1) @@ -264,7 +264,7 @@ func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address c } // IndexedLogsTopicRange provides a mock function with given fields: eventSig, address, topicIndex, topicValueMin, topicValueMax, confs, qopts -func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -276,10 +276,10 @@ func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, topicIndex, topicValueMin, topicValueMax, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, topicIndex, topicValueMin, topicValueMax, confs, qopts...) } else { if ret.Get(0) != nil { @@ -287,7 +287,7 @@ func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, topicIndex, topicValueMin, topicValueMax, confs, qopts...) } else { r1 = ret.Error(1) @@ -297,7 +297,7 @@ func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. } // IndexedLogsWithSigsExcluding provides a mock function with given fields: address, eventSigA, eventSigB, topicIndex, fromBlock, toBlock, confs, qopts -func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventSigA common.Hash, eventSigB common.Hash, topicIndex int, fromBlock int64, toBlock int64, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventSigA common.Hash, eventSigB common.Hash, topicIndex int, fromBlock int64, toBlock int64, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -309,10 +309,10 @@ func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventS var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(address, eventSigA, eventSigB, topicIndex, fromBlock, toBlock, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(address, eventSigA, eventSigB, topicIndex, fromBlock, toBlock, confs, qopts...) } else { if ret.Get(0) != nil { @@ -320,7 +320,7 @@ func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventS } } - if rf, ok := ret.Get(1).(func(common.Address, common.Hash, common.Hash, int, int64, int64, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Address, common.Hash, common.Hash, int, int64, int64, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(address, eventSigA, eventSigB, topicIndex, fromBlock, toBlock, confs, qopts...) } else { r1 = ret.Error(1) @@ -360,7 +360,7 @@ func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (int64, error) { } // LatestBlockByEventSigsAddrsWithConfs provides a mock function with given fields: fromBlock, eventSigs, addresses, confs, qopts -func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) { +func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs logpoller.Confirmations, qopts ...pg.QOpt) (int64, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -372,16 +372,16 @@ func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, event var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) (int64, error)); ok { + if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) (int64, error)); ok { return rf(fromBlock, eventSigs, addresses, confs, qopts...) } - if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) int64); ok { + if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) int64); ok { r0 = rf(fromBlock, eventSigs, addresses, confs, qopts...) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(fromBlock, eventSigs, addresses, confs, qopts...) } else { r1 = ret.Error(1) @@ -391,7 +391,7 @@ func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, event } // LatestLogByEventSigWithConfs provides a mock function with given fields: eventSig, address, confs, qopts -func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*logpoller.Log, error) { +func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs logpoller.Confirmations, qopts ...pg.QOpt) (*logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -403,10 +403,10 @@ func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address var r0 *logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, ...pg.QOpt) (*logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, logpoller.Confirmations, ...pg.QOpt) (*logpoller.Log, error)); ok { return rf(eventSig, address, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, ...pg.QOpt) *logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, logpoller.Confirmations, ...pg.QOpt) *logpoller.Log); ok { r0 = rf(eventSig, address, confs, qopts...) } else { if ret.Get(0) != nil { @@ -414,7 +414,7 @@ func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, confs, qopts...) } else { r1 = ret.Error(1) @@ -424,7 +424,7 @@ func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address } // LatestLogEventSigsAddrsWithConfs provides a mock function with given fields: fromBlock, eventSigs, addresses, confs, qopts -func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -436,10 +436,10 @@ func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(fromBlock, eventSigs, addresses, confs, qopts...) } - if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(fromBlock, eventSigs, addresses, confs, qopts...) } else { if ret.Get(0) != nil { @@ -447,7 +447,7 @@ func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs } } - if rf, ok := ret.Get(1).(func(int64, []common.Hash, []common.Address, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(fromBlock, eventSigs, addresses, confs, qopts...) } else { r1 = ret.Error(1) @@ -490,7 +490,7 @@ func (_m *LogPoller) Logs(start int64, end int64, eventSig common.Hash, address } // LogsCreatedAfter provides a mock function with given fields: eventSig, address, _a2, confs, qopts -func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Address, _a2 time.Time, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Address, _a2 time.Time, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -502,10 +502,10 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, _a2, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, _a2, confs, qopts...) } else { if ret.Get(0) != nil { @@ -513,7 +513,7 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, time.Time, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, time.Time, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, _a2, confs, qopts...) } else { r1 = ret.Error(1) @@ -523,7 +523,7 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre } // LogsDataWordGreaterThan provides a mock function with given fields: eventSig, address, wordIndex, wordValueMin, confs, qopts -func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -535,10 +535,10 @@ func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address commo var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, wordIndex, wordValueMin, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, wordIndex, wordValueMin, confs, qopts...) } else { if ret.Get(0) != nil { @@ -546,7 +546,7 @@ func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address commo } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, wordIndex, wordValueMin, confs, qopts...) } else { r1 = ret.Error(1) @@ -556,7 +556,7 @@ func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address commo } // LogsDataWordRange provides a mock function with given fields: eventSig, address, wordIndex, wordValueMin, wordValueMax, confs, qopts -func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, wordValueMax common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -568,10 +568,10 @@ func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Addr var r0 []logpoller.Log var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) ([]logpoller.Log, error)); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { return rf(eventSig, address, wordIndex, wordValueMin, wordValueMax, confs, qopts...) } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) []logpoller.Log); ok { + if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) []logpoller.Log); ok { r0 = rf(eventSig, address, wordIndex, wordValueMin, wordValueMax, confs, qopts...) } else { if ret.Get(0) != nil { @@ -579,7 +579,7 @@ func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Addr } } - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, common.Hash, int, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) error); ok { r1 = rf(eventSig, address, wordIndex, wordValueMin, wordValueMax, confs, qopts...) } else { r1 = ret.Error(1) @@ -588,39 +588,6 @@ func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Addr return r0, r1 } -// LogsUntilBlockHashDataWordGreaterThan provides a mock function with given fields: eventSig, address, wordIndex, wordValueMin, untilBlockHash, qopts -func (_m *LogPoller) LogsUntilBlockHashDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]logpoller.Log, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, eventSig, address, wordIndex, wordValueMin, untilBlockHash) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []logpoller.Log - var r1 error - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { - return rf(eventSig, address, wordIndex, wordValueMin, untilBlockHash, qopts...) - } - if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, ...pg.QOpt) []logpoller.Log); ok { - r0 = rf(eventSig, address, wordIndex, wordValueMin, untilBlockHash, qopts...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]logpoller.Log) - } - } - - if rf, ok := ret.Get(1).(func(common.Hash, common.Address, int, common.Hash, common.Hash, ...pg.QOpt) error); ok { - r1 = rf(eventSig, address, wordIndex, wordValueMin, untilBlockHash, qopts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // LogsWithSigs provides a mock function with given fields: start, end, eventSigs, address, qopts func (_m *LogPoller) LogsWithSigs(start int64, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { _va := make([]interface{}, len(qopts)) @@ -757,13 +724,12 @@ func (_m *LogPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { return r0 } -type mockConstructorTestingTNewLogPoller interface { +// NewLogPoller creates a new instance of LogPoller. 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 NewLogPoller(t interface { mock.TestingT Cleanup(func()) -} - -// NewLogPoller creates a new instance of LogPoller. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLogPoller(t mockConstructorTestingTNewLogPoller) *LogPoller { +}) *LogPoller { mock := &LogPoller{} mock.Mock.Test(t) diff --git a/core/chains/evm/logpoller/models.go b/core/chains/evm/logpoller/models.go index 2848239e67f..9c55786777c 100644 --- a/core/chains/evm/logpoller/models.go +++ b/core/chains/evm/logpoller/models.go @@ -16,9 +16,10 @@ type LogPollerBlock struct { EvmChainId *utils.Big BlockHash common.Hash // Note geth uses int64 internally https://github.com/ethereum/go-ethereum/blob/f66f1a16b3c480d3a43ac7e8a09ab3e362e96ae4/eth/filters/api.go#L340 - BlockNumber int64 - BlockTimestamp time.Time - CreatedAt time.Time + BlockNumber int64 + BlockTimestamp time.Time + FinalizedBlockNumber int64 + CreatedAt time.Time } // Log represents an EVM log. diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go index 8dfa6e81d0d..7f54fa9f09a 100644 --- a/core/chains/evm/logpoller/observability.go +++ b/core/chains/evm/logpoller/observability.go @@ -1,11 +1,13 @@ package logpoller import ( + "math/big" "time" "github.com/ethereum/go-ethereum/common" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -46,113 +48,193 @@ var ( }, []string{"evmChainID", "query"}) ) -// ObservedLogPoller is a decorator layer for LogPoller, responsible for pushing Prometheus metrics reporting duration and size of result set for some of the queries. -// It doesn't change internal logic, because all calls are delegated to the origin LogPoller -type ObservedLogPoller struct { - LogPoller +// ObservedORM is a decorator layer for ORM used by LogPoller, responsible for pushing Prometheus metrics reporting duration and size of result set for the queries. +// It doesn't change internal logic, because all calls are delegated to the origin ORM +type ObservedORM struct { + ORM queryDuration *prometheus.HistogramVec datasetSize *prometheus.GaugeVec chainId string } -// NewObservedLogPoller creates an observed version of log poller created by NewLogPoller +// NewObservedORM creates an observed version of log poller's ORM created by NewORM // Please see ObservedLogPoller for more details on how latencies are measured -func NewObservedLogPoller(orm *ORM, ec Client, lggr logger.Logger, pollPeriod time.Duration, - finalityDepth int64, backfillBatchSize int64, rpcBatchSize int64, keepBlocksDepth int64) LogPoller { - - return &ObservedLogPoller{ - LogPoller: NewLogPoller(orm, ec, lggr, pollPeriod, finalityDepth, backfillBatchSize, rpcBatchSize, keepBlocksDepth), +func NewObservedORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *ObservedORM { + return &ObservedORM{ + ORM: NewORM(chainID, db, lggr, cfg), queryDuration: lpQueryDuration, datasetSize: lpQueryDataSets, - chainId: orm.chainID.String(), + chainId: chainID.String(), } } -func (o *ObservedLogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Address, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "LogsCreatedAfter", func() ([]Log, error) { - return o.LogPoller.LogsCreatedAfter(eventSig, address, after, confs, qopts...) +func (o *ObservedORM) Q() pg.Q { + return o.ORM.Q() +} + +func (o *ObservedORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { + return withObservedExec(o, "InsertLogs", func() error { + return o.ORM.InsertLogs(logs, qopts...) }) } -func (o *ObservedLogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) { - return withObservedQuery(o, "LatestLogByEventSigWithConfs", func() (*Log, error) { - return o.LogPoller.LatestLogByEventSigWithConfs(eventSig, address, confs, qopts...) +func (o *ObservedORM) InsertBlock(hash common.Hash, blockNumber int64, blockTimestamp time.Time, lastFinalizedBlock int64, qopts ...pg.QOpt) error { + return withObservedExec(o, "InsertBlock", func() error { + return o.ORM.InsertBlock(hash, blockNumber, blockTimestamp, lastFinalizedBlock, qopts...) }) } -func (o *ObservedLogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "LatestLogEventSigsAddrsWithConfs", func() ([]Log, error) { - return o.LogPoller.LatestLogEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) +func (o *ObservedORM) InsertFilter(filter Filter, qopts ...pg.QOpt) error { + return withObservedExec(o, "InsertFilter", func() error { + return o.ORM.InsertFilter(filter, qopts...) }) } -func (o *ObservedLogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) { - return withObservedQuery(o, "LatestBlockByEventSigsAddrsWithConfs", func() (int64, error) { - return o.LogPoller.LatestBlockByEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) +func (o *ObservedORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { + return withObservedQuery(o, "LoadFilters", func() (map[string]Filter, error) { + return o.ORM.LoadFilters(qopts...) }) } -func (o *ObservedLogPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogs", func() ([]Log, error) { - return o.LogPoller.IndexedLogs(eventSig, address, topicIndex, topicValues, confs, qopts...) +func (o *ObservedORM) DeleteFilter(name string, qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteFilter", func() error { + return o.ORM.DeleteFilter(name, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsByBlockRange(start, end int64, eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsByBlockRange", func() ([]Log, error) { - return o.LogPoller.IndexedLogsByBlockRange(start, end, eventSig, address, topicIndex, topicValues, qopts...) +func (o *ObservedORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteBlocksAfter", func() error { + return o.ORM.DeleteBlocksAfter(start, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsCreatedAfter", func() ([]Log, error) { - return o.LogPoller.IndexedLogsCreatedAfter(eventSig, address, topicIndex, topicValues, after, confs, qopts...) +func (o *ObservedORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteBlocksBefore", func() error { + return o.ORM.DeleteBlocksBefore(end, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { +func (o *ObservedORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteLogsAfter", func() error { + return o.ORM.DeleteLogsAfter(start, qopts...) + }) +} + +func (o *ObservedORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { + return withObservedExec(o, "DeleteExpiredLogs", func() error { + return o.ORM.DeleteExpiredLogs(qopts...) + }) +} + +func (o *ObservedORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { + return withObservedQuery(o, "SelectBlockByNumber", func() (*LogPollerBlock, error) { + return o.ORM.SelectBlockByNumber(n, qopts...) + }) +} + +func (o *ObservedORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { + return withObservedQuery(o, "SelectLatestBlock", func() (*LogPollerBlock, error) { + return o.ORM.SelectLatestBlock(qopts...) + }) +} + +func (o *ObservedORM) SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) { + return withObservedQuery(o, "SelectLatestLogByEventSigWithConfs", func() (*Log, error) { + return o.ORM.SelectLatestLogByEventSigWithConfs(eventSig, address, confs, qopts...) + }) +} + +func (o *ObservedORM) SelectLogsWithSigs(start, end int64, address common.Address, eventSigs []common.Hash, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogsWithSigs", func() ([]Log, error) { + return o.ORM.SelectLogsWithSigs(start, end, address, eventSigs, qopts...) + }) +} + +func (o *ObservedORM) SelectLogsCreatedAfter(address common.Address, eventSig common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogsCreatedAfter", func() ([]Log, error) { + return o.ORM.SelectLogsCreatedAfter(address, eventSig, after, confs, qopts...) + }) +} + +func (o *ObservedORM) SelectIndexedLogs(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogs", func() ([]Log, error) { + return o.ORM.SelectIndexedLogs(address, eventSig, topicIndex, topicValues, confs, qopts...) + }) +} + +func (o *ObservedORM) SelectIndexedLogsByBlockRange(start, end int64, address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsByBlockRange", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsByBlockRange(start, end, address, eventSig, topicIndex, topicValues, qopts...) + }) +} + +func (o *ObservedORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsCreatedAfter", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsCreatedAfter(address, eventSig, topicIndex, topicValues, after, confs, qopts...) + }) +} + +func (o *ObservedORM) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIndex int, address common.Address, startBlock, endBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsWithSigsExcluding", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsWithSigsExcluding(sigA, sigB, topicIndex, address, startBlock, endBlock, confs, qopts...) + }) +} + +func (o *ObservedORM) SelectLogs(start, end int64, address common.Address, eventSig common.Hash, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogs", func() ([]Log, error) { + return o.ORM.SelectLogs(start, end, address, eventSig, qopts...) + }) +} + +func (o *ObservedORM) IndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { return withObservedQueryAndResults(o, "IndexedLogsByTxHash", func() ([]Log, error) { - return o.LogPoller.IndexedLogsByTxHash(eventSig, txHash, qopts...) + return o.ORM.SelectIndexedLogsByTxHash(eventSig, txHash, qopts...) + }) +} + +func (o *ObservedORM) GetBlocksRange(start int64, end int64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { + return withObservedQueryAndResults(o, "GetBlocksRange", func() ([]LogPollerBlock, error) { + return o.ORM.GetBlocksRange(start, end, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsTopicGreaterThan", func() ([]Log, error) { - return o.LogPoller.IndexedLogsTopicGreaterThan(eventSig, address, topicIndex, topicValueMin, confs, qopts...) +func (o *ObservedORM) SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresses []common.Address, eventSigs []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLatestLogEventSigsAddrsWithConfs", func() ([]Log, error) { + return o.ORM.SelectLatestLogEventSigsAddrsWithConfs(fromBlock, addresses, eventSigs, confs, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common.Address, topicIndex int, topicValueMin common.Hash, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsTopicRange", func() ([]Log, error) { - return o.LogPoller.IndexedLogsTopicRange(eventSig, address, topicIndex, topicValueMin, topicValueMax, confs, qopts...) +func (o *ObservedORM) SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) { + return withObservedQuery(o, "SelectLatestBlockByEventSigsAddrsWithConfs", func() (int64, error) { + return o.ORM.SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock, eventSigs, addresses, confs, qopts...) }) } -func (o *ObservedLogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventSigA, eventSigB common.Hash, topicIndex int, fromBlock, toBlock int64, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "IndexedLogsWithSigsExcluding", func() ([]Log, error) { - return o.LogPoller.IndexedLogsWithSigsExcluding(address, eventSigA, eventSigB, topicIndex, fromBlock, toBlock, confs, qopts...) +func (o *ObservedORM) SelectLogsDataWordRange(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogsDataWordRange", func() ([]Log, error) { + return o.ORM.SelectLogsDataWordRange(address, eventSig, wordIndex, wordValueMin, wordValueMax, confs, qopts...) }) } -func (o *ObservedLogPoller) LogsDataWordRange(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "LogsDataWordRange", func() ([]Log, error) { - return o.LogPoller.LogsDataWordRange(eventSig, address, wordIndex, wordValueMin, wordValueMax, confs, qopts...) +func (o *ObservedORM) SelectLogsDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectLogsDataWordGreaterThan", func() ([]Log, error) { + return o.ORM.SelectLogsDataWordGreaterThan(address, eventSig, wordIndex, wordValueMin, confs, qopts...) }) } -func (o *ObservedLogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "LogsDataWordGreaterThan", func() ([]Log, error) { - return o.LogPoller.LogsDataWordGreaterThan(eventSig, address, wordIndex, wordValueMin, confs, qopts...) +func (o *ObservedORM) SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsTopicGreaterThan", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsTopicGreaterThan(address, eventSig, topicIndex, topicValueMin, confs, qopts...) }) } -func (o *ObservedLogPoller) LogsUntilBlockHashDataWordGreaterThan(eventSig common.Hash, address common.Address, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - return withObservedQueryAndResults(o, "LogsUntilBlockHashDataWordGreaterThan", func() ([]Log, error) { - return o.LogPoller.LogsUntilBlockHashDataWordGreaterThan(eventSig, address, wordIndex, wordValueMin, untilBlockHash, qopts...) +func (o *ObservedORM) SelectIndexedLogsTopicRange(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + return withObservedQueryAndResults(o, "SelectIndexedLogsTopicRange", func() ([]Log, error) { + return o.ORM.SelectIndexedLogsTopicRange(address, eventSig, topicIndex, topicValueMin, topicValueMax, confs, qopts...) }) } -func withObservedQueryAndResults[T any](o *ObservedLogPoller, queryName string, query func() ([]T, error)) ([]T, error) { +func withObservedQueryAndResults[T any](o *ObservedORM, queryName string, query func() ([]T, error)) ([]T, error) { results, err := withObservedQuery(o, queryName, query) if err == nil { o.datasetSize. @@ -162,7 +244,7 @@ func withObservedQueryAndResults[T any](o *ObservedLogPoller, queryName string, return results, err } -func withObservedQuery[T any](o *ObservedLogPoller, queryName string, query func() (T, error)) (T, error) { +func withObservedQuery[T any](o *ObservedORM, queryName string, query func() (T, error)) (T, error) { queryStarted := time.Now() defer func() { o.queryDuration. @@ -171,3 +253,13 @@ func withObservedQuery[T any](o *ObservedLogPoller, queryName string, query func }() return query() } + +func withObservedExec(o *ObservedORM, query string, exec func() error) error { + queryStarted := time.Now() + defer func() { + o.queryDuration. + WithLabelValues(o.chainId, query). + Observe(float64(time.Since(queryStarted))) + }() + return exec() +} diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index 5bd0a772d96..0d3eadf47d7 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -22,99 +22,89 @@ import ( func TestMultipleMetricsArePublished(t *testing.T) { ctx := testutils.Context(t) - lp := createObservedPollLogger(t, 100) - require.Equal(t, 0, testutil.CollectAndCount(lp.queryDuration)) - - _, _ = lp.IndexedLogs(common.Hash{}, common.Address{}, 1, []common.Hash{}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.IndexedLogsByBlockRange(0, 1, common.Hash{}, common.Address{}, 1, []common.Hash{}, pg.WithParentCtx(ctx)) - _, _ = lp.IndexedLogsTopicGreaterThan(common.Hash{}, common.Address{}, 1, common.Hash{}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.IndexedLogsTopicRange(common.Hash{}, common.Address{}, 1, common.Hash{}, common.Hash{}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.IndexedLogsWithSigsExcluding(common.Address{}, common.Hash{}, common.Hash{}, 1, 0, 1, 1, pg.WithParentCtx(ctx)) - _, _ = lp.LogsDataWordRange(common.Hash{}, common.Address{}, 0, common.Hash{}, common.Hash{}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.LogsDataWordGreaterThan(common.Hash{}, common.Address{}, 0, common.Hash{}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.LogsCreatedAfter(common.Hash{}, common.Address{}, time.Now(), 0, pg.WithParentCtx(ctx)) - _, _ = lp.LatestLogByEventSigWithConfs(common.Hash{}, common.Address{}, 0, pg.WithParentCtx(ctx)) - _, _ = lp.LatestLogEventSigsAddrsWithConfs(0, []common.Hash{{}}, []common.Address{{}}, 1, pg.WithParentCtx(ctx)) - _, _ = lp.IndexedLogsCreatedAfter(common.Hash{}, common.Address{}, 0, []common.Hash{}, time.Now(), 0, pg.WithParentCtx(ctx)) - _, _ = lp.LogsUntilBlockHashDataWordGreaterThan(common.Hash{}, common.Address{}, 0, common.Hash{}, common.Hash{}, pg.WithParentCtx(ctx)) - - require.Equal(t, 12, testutil.CollectAndCount(lp.queryDuration)) - require.Equal(t, 10, testutil.CollectAndCount(lp.datasetSize)) - resetMetrics(*lp) + orm := createObservedORM(t, 100) + t.Cleanup(func() { resetMetrics(*orm) }) + require.Equal(t, 0, testutil.CollectAndCount(orm.queryDuration)) + + _, _ = orm.SelectIndexedLogs(common.Address{}, common.Hash{}, 1, []common.Hash{}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectIndexedLogsByBlockRange(0, 1, common.Address{}, common.Hash{}, 1, []common.Hash{}, pg.WithParentCtx(ctx)) + _, _ = orm.SelectIndexedLogsTopicGreaterThan(common.Address{}, common.Hash{}, 1, common.Hash{}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectIndexedLogsTopicRange(common.Address{}, common.Hash{}, 1, common.Hash{}, common.Hash{}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectIndexedLogsWithSigsExcluding(common.Hash{}, common.Hash{}, 1, common.Address{}, 0, 1, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectLogsDataWordRange(common.Address{}, common.Hash{}, 0, common.Hash{}, common.Hash{}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectLogsDataWordGreaterThan(common.Address{}, common.Hash{}, 0, common.Hash{}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectLogsCreatedAfter(common.Address{}, common.Hash{}, time.Now(), 0, pg.WithParentCtx(ctx)) + _, _ = orm.SelectLatestLogByEventSigWithConfs(common.Hash{}, common.Address{}, 0, pg.WithParentCtx(ctx)) + _, _ = orm.SelectLatestLogEventSigsAddrsWithConfs(0, []common.Address{{}}, []common.Hash{{}}, 1, pg.WithParentCtx(ctx)) + _, _ = orm.SelectIndexedLogsCreatedAfter(common.Address{}, common.Hash{}, 1, []common.Hash{}, time.Now(), 0, pg.WithParentCtx(ctx)) + _ = orm.InsertLogs([]Log{}, pg.WithParentCtx(ctx)) + _ = orm.InsertBlock(common.Hash{}, 1, time.Now(), 0, pg.WithParentCtx(ctx)) + + require.Equal(t, 13, testutil.CollectAndCount(orm.queryDuration)) + require.Equal(t, 10, testutil.CollectAndCount(orm.datasetSize)) } func TestShouldPublishDurationInCaseOfError(t *testing.T) { ctx := testutils.Context(t) - lp := createObservedPollLogger(t, 200) - require.Equal(t, 0, testutil.CollectAndCount(lp.queryDuration)) + orm := createObservedORM(t, 200) + t.Cleanup(func() { resetMetrics(*orm) }) + require.Equal(t, 0, testutil.CollectAndCount(orm.queryDuration)) - _, err := lp.LatestLogByEventSigWithConfs(common.Hash{}, common.Address{}, 0, pg.WithParentCtx(ctx)) + _, err := orm.SelectLatestLogByEventSigWithConfs(common.Hash{}, common.Address{}, 0, pg.WithParentCtx(ctx)) require.Error(t, err) - require.Equal(t, 1, testutil.CollectAndCount(lp.queryDuration)) - require.Equal(t, 1, counterFromHistogramByLabels(t, lp.queryDuration, "200", "LatestLogByEventSigWithConfs")) - - resetMetrics(*lp) -} - -func TestNotObservedFunctions(t *testing.T) { - ctx := testutils.Context(t) - lp := createObservedPollLogger(t, 300) - require.Equal(t, 0, testutil.CollectAndCount(lp.queryDuration)) - - _, err := lp.Logs(0, 1, common.Hash{}, common.Address{}, pg.WithParentCtx(ctx)) - require.NoError(t, err) - - _, err = lp.LogsWithSigs(0, 1, []common.Hash{{}}, common.Address{}, pg.WithParentCtx(ctx)) - require.NoError(t, err) - - require.Equal(t, 0, testutil.CollectAndCount(lp.queryDuration)) - require.Equal(t, 0, testutil.CollectAndCount(lp.datasetSize)) - resetMetrics(*lp) + require.Equal(t, 1, testutil.CollectAndCount(orm.queryDuration)) + require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "200", "SelectLatestLogByEventSigWithConfs")) } func TestMetricsAreProperlyPopulatedWithLabels(t *testing.T) { - lp := createObservedPollLogger(t, 420) + orm := createObservedORM(t, 420) + t.Cleanup(func() { resetMetrics(*orm) }) expectedCount := 9 expectedSize := 2 for i := 0; i < expectedCount; i++ { - _, err := withObservedQueryAndResults(lp, "query", func() ([]string, error) { return []string{"value1", "value2"}, nil }) + _, err := withObservedQueryAndResults(orm, "query", func() ([]string, error) { return []string{"value1", "value2"}, nil }) require.NoError(t, err) } - require.Equal(t, expectedCount, counterFromHistogramByLabels(t, lp.queryDuration, "420", "query")) - require.Equal(t, expectedSize, counterFromGaugeByLabels(lp.datasetSize, "420", "query")) - - require.Equal(t, 0, counterFromHistogramByLabels(t, lp.queryDuration, "420", "other_query")) - require.Equal(t, 0, counterFromHistogramByLabels(t, lp.queryDuration, "5", "query")) + require.Equal(t, expectedCount, counterFromHistogramByLabels(t, orm.queryDuration, "420", "query")) + require.Equal(t, expectedSize, counterFromGaugeByLabels(orm.datasetSize, "420", "query")) - require.Equal(t, 0, counterFromGaugeByLabels(lp.datasetSize, "420", "other_query")) - require.Equal(t, 0, counterFromGaugeByLabels(lp.datasetSize, "5", "query")) + require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "420", "other_query")) + require.Equal(t, 0, counterFromHistogramByLabels(t, orm.queryDuration, "5", "query")) - resetMetrics(*lp) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "other_query")) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "5", "query")) } func TestNotPublishingDatasetSizeInCaseOfError(t *testing.T) { - lp := createObservedPollLogger(t, 420) + orm := createObservedORM(t, 420) - _, err := withObservedQueryAndResults(lp, "errorQuery", func() ([]string, error) { return nil, fmt.Errorf("error") }) + _, err := withObservedQueryAndResults(orm, "errorQuery", func() ([]string, error) { return nil, fmt.Errorf("error") }) require.Error(t, err) - require.Equal(t, 1, counterFromHistogramByLabels(t, lp.queryDuration, "420", "errorQuery")) - require.Equal(t, 0, counterFromGaugeByLabels(lp.datasetSize, "420", "errorQuery")) + require.Equal(t, 1, counterFromHistogramByLabels(t, orm.queryDuration, "420", "errorQuery")) + require.Equal(t, 0, counterFromGaugeByLabels(orm.datasetSize, "420", "errorQuery")) +} + +func TestMetricsAreProperlyPopulatedForWrites(t *testing.T) { + orm := createObservedORM(t, 420) + require.NoError(t, withObservedExec(orm, "execQuery", func() error { return nil })) + require.Error(t, withObservedExec(orm, "execQuery", func() error { return fmt.Errorf("error") })) + + require.Equal(t, 2, counterFromHistogramByLabels(t, orm.queryDuration, "420", "execQuery")) } -func createObservedPollLogger(t *testing.T, chainId int64) *ObservedLogPoller { +func createObservedORM(t *testing.T, chainId int64) *ObservedORM { lggr, _ := logger.TestLoggerObserved(t, zapcore.ErrorLevel) db := pgtest.NewSqlxDB(t) - orm := NewORM(big.NewInt(chainId), db, lggr, pgtest.NewQConfig(true)) - return NewObservedLogPoller( - orm, nil, lggr, 1, 1, 1, 1, 1000, - ).(*ObservedLogPoller) + return NewObservedORM( + big.NewInt(chainId), db, lggr, pgtest.NewQConfig(true), + ) } -func resetMetrics(lp ObservedLogPoller) { +func resetMetrics(lp ObservedORM) { lp.queryDuration.Reset() lp.datasetSize.Reset() } diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index c062ef3e080..06f4acbb4f1 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -3,11 +3,11 @@ package logpoller import ( "context" "database/sql" + "fmt" "math/big" "time" "github.com/ethereum/go-ethereum/common" - "github.com/lib/pq" "github.com/pkg/errors" "github.com/smartcontractkit/sqlx" @@ -16,62 +16,117 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -type ORM struct { +// ORM represents the persistent data access layer used by the log poller. At this moment, it's a bit leaky abstraction, because +// it exposes some of the database implementation details (e.g. pg.Q). Ideally it should be agnostic and could be applied to any persistence layer. +// What is more, LogPoller should not be aware of the underlying database implementation and delegate all the queries to the ORM. +type ORM interface { + Q() pg.Q + InsertLogs(logs []Log, qopts ...pg.QOpt) error + InsertBlock(blockHash common.Hash, blockNumber int64, blockTimestamp time.Time, lastFinalizedBlockNumber int64, qopts ...pg.QOpt) error + InsertFilter(filter Filter, qopts ...pg.QOpt) error + + LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) + DeleteFilter(name string, qopts ...pg.QOpt) error + + DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error + DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error + DeleteLogsAfter(start int64, qopts ...pg.QOpt) error + DeleteExpiredLogs(qopts ...pg.QOpt) error + + GetBlocksRange(start int64, end int64, qopts ...pg.QOpt) ([]LogPollerBlock, error) + SelectBlockByNumber(blockNumber int64, qopts ...pg.QOpt) (*LogPollerBlock, error) + SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) + + SelectLogs(start, end int64, address common.Address, eventSig common.Hash, qopts ...pg.QOpt) ([]Log, error) + SelectLogsWithSigs(start, end int64, address common.Address, eventSigs []common.Hash, qopts ...pg.QOpt) ([]Log, error) + SelectLogsCreatedAfter(address common.Address, eventSig common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) + SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresses []common.Address, eventSigs []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) + + SelectIndexedLogs(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsByBlockRange(start, end int64, address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsCreatedAfter(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsTopicRange(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIndex int, address common.Address, startBlock, endBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) + SelectLogsDataWordRange(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) + SelectLogsDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) +} + +type DbORM struct { chainID *big.Int q pg.Q } -// NewORM creates an ORM scoped to chainID. -func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *ORM { +// NewORM creates a DbORM scoped to chainID. +func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *DbORM { namedLogger := lggr.Named("Configs") q := pg.NewQ(db, namedLogger, cfg) - return &ORM{ + return &DbORM{ chainID: chainID, q: q, } } +func (o *DbORM) Q() pg.Q { + return o.q +} + // InsertBlock is idempotent to support replays. -func (o *ORM) InsertBlock(h common.Hash, n int64, t time.Time, qopts ...pg.QOpt) error { - q := o.q.WithOpts(qopts...) - err := q.ExecQ(`INSERT INTO evm.log_poller_blocks (evm_chain_id, block_hash, block_number, block_timestamp, created_at) - VALUES ($1, $2, $3, $4, NOW()) ON CONFLICT DO NOTHING`, utils.NewBig(o.chainID), h[:], n, t) - return err +func (o *DbORM) InsertBlock(blockHash common.Hash, blockNumber int64, blockTimestamp time.Time, finalizedBlock int64, qopts ...pg.QOpt) error { + args, err := newQueryArgs(o.chainID). + withCustomHashArg("block_hash", blockHash). + withCustomArg("block_number", blockNumber). + withCustomArg("block_timestamp", blockTimestamp). + withCustomArg("finalized_block_number", finalizedBlock). + toArgs() + if err != nil { + return err + } + return o.q.WithOpts(qopts...).ExecQNamed(` + INSERT INTO evm.log_poller_blocks + (evm_chain_id, block_hash, block_number, block_timestamp, finalized_block_number, created_at) + VALUES (:evm_chain_id, :block_hash, :block_number, :block_timestamp, :finalized_block_number, NOW()) + ON CONFLICT DO NOTHING`, args) } // InsertFilter is idempotent. // // Each address/event pair must have a unique job id, so it may be removed when the job is deleted. // If a second job tries to overwrite the same pair, this should fail. -func (o *ORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { - q := o.q.WithOpts(qopts...) - addresses := make([][]byte, 0) - events := make([][]byte, 0) - - for _, addr := range filter.Addresses { - addresses = append(addresses, addr.Bytes()) - } - for _, ev := range filter.EventSigs { - events = append(events, ev.Bytes()) +func (o *DbORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { + args, err := newQueryArgs(o.chainID). + withCustomArg("name", filter.Name). + withCustomArg("retention", filter.Retention). + withAddressArray(filter.Addresses). + withEventSigArray(filter.EventSigs). + toArgs() + if err != nil { + return err } - return q.ExecQ(`INSERT INTO evm.log_poller_filters - (name, evm_chain_id, retention, created_at, address, event) + // '::' has to be escaped in the query string + // https://github.com/jmoiron/sqlx/issues/91, https://github.com/jmoiron/sqlx/issues/428 + return o.q.WithOpts(qopts...).ExecQNamed(` + INSERT INTO evm.log_poller_filters + (name, evm_chain_id, retention, created_at, address, event) SELECT * FROM - (SELECT $1, $2::NUMERIC, $3::BIGINT, NOW()) x, - (SELECT unnest($4::BYTEA[]) addr) a, - (SELECT unnest($5::BYTEA[]) ev) e - ON CONFLICT (name, evm_chain_id, address, event) DO UPDATE SET retention=$3::BIGINT;`, - filter.Name, utils.NewBig(o.chainID), filter.Retention, addresses, events) + (SELECT :name, :evm_chain_id ::::NUMERIC, :retention ::::BIGINT, NOW()) x, + (SELECT unnest(:address_array ::::BYTEA[]) addr) a, + (SELECT unnest(:event_sig_array ::::BYTEA[]) ev) e + ON CONFLICT (name, evm_chain_id, address, event) + DO UPDATE SET retention=:retention ::::BIGINT`, args) } // DeleteFilter removes all events,address pairs associated with the Filter -func (o *ORM) DeleteFilter(name string, qopts ...pg.QOpt) error { +func (o *DbORM) DeleteFilter(name string, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, utils.NewBig(o.chainID)) } // LoadFiltersForChain returns all filters for this chain -func (o *ORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { +func (o *DbORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { q := o.q.WithOpts(qopts...) rows := make([]Filter, 0) err := q.Select(&rows, `SELECT name, @@ -88,16 +143,16 @@ func (o *ORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { return filters, err } -func (o *ORM) SelectBlockByHash(h common.Hash, qopts ...pg.QOpt) (*LogPollerBlock, error) { +func (o *DbORM) SelectBlockByHash(hash common.Hash, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, h, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, hash, utils.NewBig(o.chainID)); err != nil { return nil, err } return &b, nil } -func (o *ORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { +func (o *DbORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, utils.NewBig(o.chainID)); err != nil { @@ -106,7 +161,7 @@ func (o *ORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, e return &b, nil } -func (o *ORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { +func (o *DbORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, utils.NewBig(o.chainID)); err != nil { @@ -115,34 +170,41 @@ func (o *ORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { return &b, nil } -func (o *ORM) SelectLatestLogEventSigWithConfs(eventSig common.Hash, address common.Address, confs int, qopts ...pg.QOpt) (*Log, error) { - q := o.q.WithOpts(qopts...) +func (o *DbORM) SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address common.Address, confs Confirmations, qopts ...pg.QOpt) (*Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withConfs(confs). + toArgs() + if err != nil { + return nil, err + } + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND event_sig = :event_sig + AND address = :address + AND block_number <= %s + ORDER BY (block_number, log_index) DESC LIMIT 1`, nestedBlockNumberQuery(confs)) var l Log - if err := q.Get(&l, `SELECT * FROM evm.logs - WHERE evm_chain_id = $1 - AND event_sig = $2 - AND address = $3 - AND (block_number + $4) <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - ORDER BY (block_number, log_index) DESC LIMIT 1`, utils.NewBig(o.chainID), eventSig, address, confs); err != nil { + if err := o.q.WithOpts(qopts...).GetNamed(query, &l, args); err != nil { return nil, err } return &l, nil } // DeleteBlocksAfter delete all blocks after and including start. -func (o *ORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { +func (o *DbORM) DeleteBlocksAfter(start int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) return q.ExecQ(`DELETE FROM evm.log_poller_blocks WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) } // DeleteBlocksBefore delete all blocks before and including end. -func (o *ORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { +func (o *DbORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, utils.NewBig(o.chainID)) return err } -func (o *ORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { +func (o *DbORM) DeleteLogsAfter(start int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) return q.ExecQ(`DELETE FROM evm.logs WHERE block_number >= $1 AND evm_chain_id = $2`, start, utils.NewBig(o.chainID)) } @@ -155,7 +217,7 @@ type Exp struct { ShouldDelete bool } -func (o *ORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { +func (o *DbORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { qopts = append(qopts, pg.WithLongQueryTimeout()) q := o.q.WithOpts(qopts...) @@ -170,7 +232,7 @@ func (o *ORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { } // InsertLogs is idempotent to support replays. -func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { +func (o *DbORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { for _, log := range logs { if o.chainID.Cmp(log.EvmChainId.ToInt()) != 0 { return errors.Errorf("invalid chainID in log got %v want %v", log.EvmChainId.ToInt(), o.chainID) @@ -185,9 +247,12 @@ func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { end = len(logs) } - err := q.ExecQNamed(`INSERT INTO evm.logs -(evm_chain_id, log_index, block_hash, block_number, block_timestamp, address, event_sig, topics, tx_hash, data, created_at) VALUES -(:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) ON CONFLICT DO NOTHING`, logs[start:end]) + err := q.ExecQNamed(` + INSERT INTO evm.logs + (evm_chain_id, log_index, block_hash, block_number, block_timestamp, address, event_sig, topics, tx_hash, data, created_at) + VALUES + (:evm_chain_id, :log_index, :block_hash, :block_number, :block_timestamp, :address, :event_sig, :topics, :tx_hash, :data, NOW()) + ON CONFLICT DO NOTHING`, logs[start:end]) if err != nil { if errors.Is(err, context.DeadlineExceeded) && batchInsertSize > 500 { @@ -199,16 +264,25 @@ func (o *ORM) InsertLogs(logs []Log, qopts ...pg.QOpt) error { return err } } - return nil } -func (o *ORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { +func (o *DbORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { + args, err := newQueryArgs(o.chainID). + withStartBlock(start). + withEndBlock(end). + toArgs() + if err != nil { + return nil, err + } + var logs []Log - err := o.q.Select(&logs, ` + err = o.q.SelectNamed(&logs, ` SELECT * FROM evm.logs - WHERE block_number >= $1 AND block_number <= $2 AND evm_chain_id = $3 - ORDER BY (block_number, log_index, created_at)`, start, end, utils.NewBig(o.chainID)) + WHERE evm_chain_id = :evm_chain_id + AND block_number >= :start_block + AND block_number <= :end_block + ORDER BY (block_number, log_index, created_at)`, args) if err != nil { return nil, err } @@ -216,14 +290,23 @@ func (o *ORM) SelectLogsByBlockRange(start, end int64) ([]Log, error) { } // SelectLogsByBlockRangeFilter finds the logs in a given block range. -func (o *ORM) SelectLogsByBlockRangeFilter(start, end int64, address common.Address, eventSig common.Hash, qopts ...pg.QOpt) ([]Log, error) { +func (o *DbORM) SelectLogs(start, end int64, address common.Address, eventSig common.Hash, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withStartBlock(start). + withEndBlock(end). + toArgs() + if err != nil { + return nil, err + } var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, ` + err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` SELECT * FROM evm.logs - WHERE evm.logs.block_number >= $1 AND evm.logs.block_number <= $2 AND evm.logs.evm_chain_id = $3 - AND address = $4 AND event_sig = $5 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes()) + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND block_number >= :start_block + AND block_number <= :end_block + ORDER BY (block_number, log_index)`, args) if err != nil { return nil, err } @@ -231,70 +314,73 @@ func (o *ORM) SelectLogsByBlockRangeFilter(start, end int64, address common.Addr } // SelectLogsCreatedAfter finds logs created after some timestamp. -func (o *ORM) SelectLogsCreatedAfter(eventSig []byte, address common.Address, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { - var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, ` - SELECT * FROM evm.logs - WHERE evm_chain_id = $1 - AND address = $2 - AND event_sig = $3 - AND created_at > $4 - AND (block_number + $5) <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - ORDER BY created_at ASC`, utils.NewBig(o.chainID), address, eventSig, after, confs) +func (o *DbORM) SelectLogsCreatedAfter(address common.Address, eventSig common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withBlockTimestampAfter(after). + withConfs(confs). + toArgs() if err != nil { return nil, err } + + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND block_timestamp > :block_timestamp_after + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) + + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { + return nil, err + } return logs, nil } // SelectLogsWithSigsByBlockRangeFilter finds the logs in the given block range with the given event signatures // emitted from the given address. -func (o *ORM) SelectLogsWithSigsByBlockRangeFilter(start, end int64, address common.Address, eventSigs []common.Hash, qopts ...pg.QOpt) (logs []Log, err error) { - q := o.q.WithOpts(qopts...) - sigs := make([][]byte, 0, len(eventSigs)) - for _, sig := range eventSigs { - sigs = append(sigs, sig.Bytes()) - } - a := map[string]any{ - "start": start, - "end": end, - "chainid": utils.NewBig(o.chainID), - "address": address, - "EventSigs": sigs, - } - query, args, err := sqlx.Named( - ` -SELECT - * -FROM evm.logs -WHERE evm.logs.block_number BETWEEN :start AND :end - AND evm.logs.evm_chain_id = :chainid - AND evm.logs.address = :address - AND evm.logs.event_sig IN (:EventSigs) -ORDER BY (evm.logs.block_number, evm.logs.log_index)`, a) - if err != nil { - return nil, errors.Wrap(err, "sqlx Named") - } - query, args, err = sqlx.In(query, args...) +func (o *DbORM) SelectLogsWithSigs(start, end int64, address common.Address, eventSigs []common.Hash, qopts ...pg.QOpt) (logs []Log, err error) { + args, err := newQueryArgs(o.chainID). + withAddress(address). + withEventSigArray(eventSigs). + withStartBlock(start). + withEndBlock(end). + toArgs() if err != nil { - return nil, errors.Wrap(err, "sqlx In") + return nil, err } - query = q.Rebind(query) - err = q.Select(&logs, query, args...) + + q := o.q.WithOpts(qopts...) + err = q.SelectNamed(&logs, ` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = ANY(:event_sig_array) + AND block_number BETWEEN :start_block AND :end_block + ORDER BY (block_number, log_index)`, args) if errors.Is(err, sql.ErrNoRows) { return nil, nil } return logs, err } -func (o *ORM) GetBlocksRange(start uint64, end uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { +func (o *DbORM) GetBlocksRange(start int64, end int64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { + args, err := newQueryArgs(o.chainID). + withStartBlock(start). + withEndBlock(end). + toArgs() + if err != nil { + return nil, err + } var blocks []LogPollerBlock - q := o.q.WithOpts(qopts...) - err := q.Select(&blocks, ` + err = o.q.WithOpts(qopts...).SelectNamed(&blocks, ` SELECT * FROM evm.log_poller_blocks - WHERE block_number >= $1 AND block_number <= $2 AND evm_chain_id = $3 - ORDER BY block_number ASC`, start, end, utils.NewBig(o.chainID)) + WHERE block_number >= :start_block + AND block_number <= :end_block + AND evm_chain_id = :evm_chain_id + ORDER BY block_number ASC`, args) if err != nil { return nil, err } @@ -302,230 +388,252 @@ func (o *ORM) GetBlocksRange(start uint64, end uint64, qopts ...pg.QOpt) ([]LogP } // SelectLatestLogEventSigsAddrsWithConfs finds the latest log by (address, event) combination that matches a list of Addresses and list of events -func (o *ORM) SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresses []common.Address, eventSigs []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - var logs []Log - sigs := concatBytes(eventSigs) - addrs := concatBytes(addresses) - - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, ` +func (o *DbORM) SelectLatestLogEventSigsAddrsWithConfs(fromBlock int64, addresses []common.Address, eventSigs []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgs(o.chainID). + withAddressArray(addresses). + withEventSigArray(eventSigs). + withStartBlock(fromBlock). + withConfs(confs). + toArgs() + if err != nil { + return nil, err + } + query := fmt.Sprintf(` SELECT * FROM evm.logs WHERE (block_number, address, event_sig) IN ( SELECT MAX(block_number), address, event_sig FROM evm.logs - WHERE evm_chain_id = $1 AND - event_sig = ANY($2) AND - address = ANY($3) AND - block_number > $4 AND - block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5 + WHERE evm_chain_id = :evm_chain_id + AND event_sig = ANY(:event_sig_array) + AND address = ANY(:address_array) + AND block_number > :start_block + AND block_number <= %s GROUP BY event_sig, address ) - ORDER BY block_number ASC - `, o.chainID.Int64(), sigs, addrs, fromBlock, confs) - if err != nil { + ORDER BY block_number ASC`, nestedBlockNumberQuery(confs)) + var logs []Log + if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, errors.Wrap(err, "failed to execute query") } return logs, nil } // SelectLatestBlockNumberEventSigsAddrsWithConfs finds the latest block number that matches a list of Addresses and list of events. It returns 0 if there is no matching block -func (o *ORM) SelectLatestBlockNumberEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs int, qopts ...pg.QOpt) (int64, error) { - var blockNumber int64 - sigs := concatBytes(eventSigs) - addrs := concatBytes(addresses) - - q := o.q.WithOpts(qopts...) - err := q.Get(&blockNumber, ` - SELECT COALESCE(MAX(block_number), 0) FROM evm.logs - WHERE evm_chain_id = $1 AND - event_sig = ANY($2) AND - address = ANY($3) AND - block_number > $4 AND - block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $5`, - o.chainID.Int64(), sigs, addrs, fromBlock, confs) +func (o *DbORM) SelectLatestBlockByEventSigsAddrsWithConfs(fromBlock int64, eventSigs []common.Hash, addresses []common.Address, confs Confirmations, qopts ...pg.QOpt) (int64, error) { + args, err := newQueryArgs(o.chainID). + withEventSigArray(eventSigs). + withAddressArray(addresses). + withStartBlock(fromBlock). + withConfs(confs). + toArgs() if err != nil { return 0, err } + query := fmt.Sprintf(` + SELECT COALESCE(MAX(block_number), 0) FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND event_sig = ANY(:event_sig_array) + AND address = ANY(:address_array) + AND block_number > :start_block + AND block_number <= %s`, nestedBlockNumberQuery(confs)) + var blockNumber int64 + if err := o.q.WithOpts(qopts...).GetNamed(query, &blockNumber, args); err != nil { + return 0, err + } return blockNumber, nil } -func (o *ORM) SelectDataWordRange(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, - `SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND substring(data from 32*$4+1 for 32) >= $5 - AND substring(data from 32*$4+1 for 32) <= $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), wordValueMax.Bytes(), confs) +func (o *DbORM) SelectLogsDataWordRange(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin, wordValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withWordIndex(wordIndex). + withWordValueMin(wordValueMin). + withWordValueMax(wordValueMax). + withConfs(confs). + toArgs() if err != nil { return nil, err } - return logs, nil -} - -func (o *ORM) SelectDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { + query := fmt.Sprintf(`SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND substring(data from 32*:word_index+1 for 32) >= :word_value_min + AND substring(data from 32*:word_index+1 for 32) <= :word_value_max + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, - `SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND substring(data from 32*$4+1 for 32) >= $5 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), confs) - if err != nil { + if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil } -func (o *ORM) SelectIndexLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - if err := validateTopicIndex(topicIndex); err != nil { +func (o *DbORM) SelectLogsDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withWordIndex(wordIndex). + withWordValueMin(wordValueMin). + withConfs(confs). + toArgs() + if err != nil { return nil, err } - + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND substring(data from 32*:word_index+1 for 32) >= :word_value_min + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, - `SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND topics[$4] >= $5 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), confs) - if err != nil { + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil } -func (o *ORM) SelectUntilBlockHashDataWordGreaterThan(address common.Address, eventSig common.Hash, wordIndex int, wordValueMin common.Hash, untilBlockHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Transaction(func(tx pg.Queryer) error { - // We want to mimic the behaviour of the ETH RPC which errors if blockhash not found. - var block LogPollerBlock - if err := tx.Get(&block, - `SELECT * FROM evm.log_poller_blocks - WHERE evm_chain_id = $1 AND block_hash = $2`, utils.NewBig(o.chainID), untilBlockHash); err != nil { - return err - } - return q.Select(&logs, - `SELECT * FROM evm.logs - WHERE evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND substring(data from 32*$4+1 for 32) >= $5 - AND block_number <= $6 - ORDER BY (block_number, log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), wordIndex, wordValueMin.Bytes(), block.BlockNumber) - }) +func (o *DbORM) SelectIndexedLogsTopicGreaterThan(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withTopicIndex(topicIndex). + withTopicValueMin(topicValueMin). + withConfs(confs). + toArgs() if err != nil { return nil, err } + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND topics[:topic_index] >= :topic_value_min + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { + return nil, err + } return logs, nil } -func (o *ORM) SelectIndexLogsTopicRange(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin, topicValueMax common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - if err := validateTopicIndex(topicIndex); err != nil { +func (o *DbORM) SelectIndexedLogsTopicRange(address common.Address, eventSig common.Hash, topicIndex int, topicValueMin, topicValueMax common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withTopicIndex(topicIndex). + withTopicValueMin(topicValueMin). + withTopicValueMax(topicValueMax). + withConfs(confs). + toArgs() + if err != nil { return nil, err } - + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND topics[:topic_index] >= :topic_value_min + AND topics[:topic_index] <= :topic_value_max + AND block_number <= %s + ORDER BY (evm.logs.block_number, evm.logs.log_index)`, nestedBlockNumberQuery(confs)) var logs []Log - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, - `SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND topics[$4] >= $5 - AND topics[$4] <= $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValueMin.Bytes(), topicValueMax.Bytes(), confs) - if err != nil { + if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil } -func (o *ORM) SelectIndexedLogs(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]Log, error) { - if err := validateTopicIndex(topicIndex); err != nil { +func (o *DbORM) SelectIndexedLogs(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withTopicIndex(topicIndex). + withTopicValues(topicValues). + withConfs(confs). + toArgs() + if err != nil { return nil, err } - - q := o.q.WithOpts(qopts...) - var logs []Log - topicValuesBytes := concatBytes(topicValues) - // Add 1 since postgresql arrays are 1-indexed. - err := q.Select(&logs, ` + query := fmt.Sprintf(` SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND topics[$4] = ANY($5) - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $6 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes, confs) - if err != nil { + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND topics[:topic_index] = ANY(:topic_values) + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) + var logs []Log + if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil } // SelectIndexedLogsByBlockRangeFilter finds the indexed logs in a given block range. -func (o *ORM) SelectIndexedLogsByBlockRangeFilter(start, end int64, address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) { - if err := validateTopicIndex(topicIndex); err != nil { +func (o *DbORM) SelectIndexedLogsByBlockRange(start, end int64, address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withTopicIndex(topicIndex). + withTopicValues(topicValues). + withStartBlock(start). + withEndBlock(end). + toArgs() + if err != nil { return nil, err } - var logs []Log - topicValuesBytes := concatBytes(topicValues) - q := o.q.WithOpts(qopts...) - err := q.Select(&logs, ` + err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` SELECT * FROM evm.logs - WHERE evm.logs.block_number >= $1 AND evm.logs.block_number <= $2 AND evm.logs.evm_chain_id = $3 - AND address = $4 AND event_sig = $5 - AND topics[$6] = ANY($7) - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, start, end, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes) + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND topics[:topic_index] = ANY(:topic_values) + AND block_number >= :start_block + AND block_number <= :end_block + ORDER BY (block_number, log_index)`, args) if err != nil { return nil, err } return logs, nil } -func validateTopicIndex(index int) error { - // Only topicIndex 1 through 3 is valid. 0 is the event sig and only 4 total topics are allowed - if !(index == 1 || index == 2 || index == 3) { - return errors.Errorf("invalid index for topic: %d", index) +func (o *DbORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, after time.Time, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgsForEvent(o.chainID, address, eventSig). + withBlockTimestampAfter(after). + withConfs(confs). + withTopicIndex(topicIndex). + withTopicValues(topicValues). + toArgs() + if err != nil { + return nil, err } - return nil -} -func (o *ORM) SelectIndexedLogsCreatedAfter(address common.Address, eventSig common.Hash, topicIndex int, topicValues []common.Hash, after time.Time, confs int, qopts ...pg.QOpt) ([]Log, error) { - q := o.q.WithOpts(qopts...) - var logs []Log - topicValuesBytes := concatBytes(topicValues) - // Add 1 since postgresql arrays are 1-indexed. - err := q.Select(&logs, ` + query := fmt.Sprintf(` SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND address = $2 AND event_sig = $3 - AND topics[$4] = ANY($5) - AND created_at > $6 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $7 - ORDER BY created_at ASC`, utils.NewBig(o.chainID), address, eventSig.Bytes(), topicIndex+1, topicValuesBytes, after, confs) - if err != nil { + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :event_sig + AND topics[:topic_index] = ANY(:topic_values) + AND block_timestamp > :block_timestamp_after + AND block_number <= %s + ORDER BY (block_number, log_index)`, nestedBlockNumberQuery(confs)) + + var logs []Log + if err = o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil } -func (o *ORM) SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { - q := o.q.WithOpts(qopts...) +func (o *DbORM) SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgs(o.chainID). + withTxHash(txHash). + withEventSig(eventSig). + toArgs() + if err != nil { + return nil, err + } var logs []Log - err := q.Select(&logs, ` + err = o.q.WithOpts(qopts...).SelectNamed(&logs, ` SELECT * FROM evm.logs - WHERE evm.logs.evm_chain_id = $1 - AND tx_hash = $2 - AND event_sig = $3 - ORDER BY (evm.logs.block_number, evm.logs.log_index)`, - utils.NewBig(o.chainID), txHash.Bytes(), eventSig.Bytes()) + WHERE evm_chain_id = :evm_chain_id + AND tx_hash = :tx_hash + AND event_sig = :event_sig + ORDER BY (block_number, log_index)`, args) if err != nil { return nil, err } @@ -533,53 +641,60 @@ func (o *ORM) SelectIndexedLogsByTxHash(eventSig common.Hash, txHash common.Hash } // SelectIndexedLogsWithSigsExcluding query's for logs that have signature A and exclude logs that have a corresponding signature B, matching is done based on the topic index both logs should be inside the block range and have the minimum number of confirmations -func (o *ORM) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIndex int, address common.Address, startBlock, endBlock int64, confs int, qopts ...pg.QOpt) ([]Log, error) { - if err := validateTopicIndex(topicIndex); err != nil { +func (o *DbORM) SelectIndexedLogsWithSigsExcluding(sigA, sigB common.Hash, topicIndex int, address common.Address, startBlock, endBlock int64, confs Confirmations, qopts ...pg.QOpt) ([]Log, error) { + args, err := newQueryArgs(o.chainID). + withAddress(address). + withTopicIndex(topicIndex). + withStartBlock(startBlock). + withEndBlock(endBlock). + withCustomHashArg("sigA", sigA). + withCustomHashArg("sigB", sigB). + withConfs(confs). + toArgs() + if err != nil { return nil, err } - q := o.q.WithOpts(qopts...) - var logs []Log - - err := q.Select(&logs, ` - SELECT * - FROM evm.logs - WHERE evm_chain_id = $1 - AND address = $2 - AND event_sig = $3 - AND block_number BETWEEN $6 AND $7 - AND block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 - + nestedQuery := nestedBlockNumberQuery(confs) + query := fmt.Sprintf(` + SELECT * FROM evm.logs + WHERE evm_chain_id = :evm_chain_id + AND address = :address + AND event_sig = :sigA + AND block_number BETWEEN :start_block AND :end_block + AND block_number <= %s EXCEPT - - SELECT a.* - FROM evm.logs AS a + SELECT a.* FROM evm.logs AS a INNER JOIN evm.logs B ON a.evm_chain_id = b.evm_chain_id AND a.address = b.address - AND a.topics[$5] = b.topics[$5] - AND a.event_sig = $3 - AND b.event_sig = $4 - AND b.block_number BETWEEN $6 AND $7 - AND b.block_number <= (SELECT COALESCE(block_number, 0) FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1) - $8 - - ORDER BY block_number,log_index ASC - `, utils.NewBig(o.chainID), address, sigA.Bytes(), sigB.Bytes(), topicIndex+1, startBlock, endBlock, confs) - if err != nil { + AND a.topics[:topic_index] = b.topics[:topic_index] + AND a.event_sig = :sigA + AND b.event_sig = :sigB + AND b.block_number BETWEEN :start_block AND :end_block + AND b.block_number <= %s + ORDER BY block_number,log_index ASC`, nestedQuery, nestedQuery) + var logs []Log + if err := o.q.WithOpts(qopts...).SelectNamed(&logs, query, args); err != nil { return nil, err } return logs, nil - } -type bytesProducer interface { - Bytes() []byte -} - -func concatBytes[T bytesProducer](byteSlice []T) pq.ByteaArray { - var output [][]byte - for _, b := range byteSlice { - output = append(output, b.Bytes()) +func nestedBlockNumberQuery(confs Confirmations) string { + if confs == Finalized { + return ` + (SELECT finalized_block_number + FROM evm.log_poller_blocks + WHERE evm_chain_id = :evm_chain_id + ORDER BY block_number DESC LIMIT 1) ` } - return output + // Intentionally wrap with greatest() function and don't return negative block numbers when :confs > :block_number + // It doesn't impact logic of the outer query, because block numbers are never less or equal to 0 (guarded by log_poller_blocks_block_number_check) + return ` + (SELECT greatest(block_number - :confs, 0) + FROM evm.log_poller_blocks + WHERE evm_chain_id = :evm_chain_id + ORDER BY block_number DESC LIMIT 1) ` + } diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 28f3e8da8e6..66e1afdc939 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -27,22 +27,27 @@ type block struct { } func GenLog(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address) logpoller.Log { + return GenLogWithTimestamp(chainID, logIndex, blockNum, blockHash, topic1, address, time.Now()) +} + +func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address, blockTimestamp time.Time) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), - LogIndex: logIndex, - BlockHash: common.HexToHash(blockHash), - BlockNumber: blockNum, - EventSig: common.BytesToHash(topic1), - Topics: [][]byte{topic1}, - Address: address, - TxHash: common.HexToHash("0x1234"), - Data: append([]byte("hello "), byte(blockNum)), + EvmChainId: utils.NewBig(chainID), + LogIndex: logIndex, + BlockHash: common.HexToHash(blockHash), + BlockNumber: blockNum, + EventSig: common.BytesToHash(topic1), + Topics: [][]byte{topic1, topic1}, + Address: address, + TxHash: common.HexToHash("0x1234"), + Data: append([]byte("hello "), byte(blockNum)), + BlockTimestamp: blockTimestamp, } } func TestLogPoller_Batching(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) var logs []logpoller.Log // Inserts are limited to 65535 parameters. A log being 10 parameters this results in // a maximum of 6553 log inserts per tx. As inserting more than 6553 would result in @@ -58,7 +63,7 @@ func TestLogPoller_Batching(t *testing.T) { } func TestORM_GetBlocks_From_Range(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM // Insert many blocks and read them back together blocks := []block{ @@ -89,12 +94,12 @@ func TestORM_GetBlocks_From_Range(t *testing.T) { }, } for _, b := range blocks { - require.NoError(t, o1.InsertBlock(b.hash, b.number, time.Unix(b.timestamp, 0).UTC())) + require.NoError(t, o1.InsertBlock(b.hash, b.number, time.Unix(b.timestamp, 0).UTC(), 0)) } - var blockNumbers []uint64 + var blockNumbers []int64 for _, b := range blocks { - blockNumbers = append(blockNumbers, uint64(b.number)) + blockNumbers = append(blockNumbers, b.number) } lpBlocks, err := o1.GetBlocksRange(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) @@ -113,7 +118,7 @@ func TestORM_GetBlocks_From_Range(t *testing.T) { } func TestORM_GetBlocks_From_Range_Recent_Blocks(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM // Insert many blocks and read them back together var recentBlocks []block @@ -121,12 +126,12 @@ func TestORM_GetBlocks_From_Range_Recent_Blocks(t *testing.T) { recentBlocks = append(recentBlocks, block{number: int64(i), hash: common.HexToHash(fmt.Sprintf("0x%d", i))}) } for _, b := range recentBlocks { - require.NoError(t, o1.InsertBlock(b.hash, b.number, time.Now())) + require.NoError(t, o1.InsertBlock(b.hash, b.number, time.Now(), 0)) } - var blockNumbers []uint64 + var blockNumbers []int64 for _, b := range recentBlocks { - blockNumbers = append(blockNumbers, uint64(b.number)) + blockNumbers = append(blockNumbers, b.number) } lpBlocks, err := o1.GetBlocksRange(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) @@ -145,11 +150,11 @@ func TestORM_GetBlocks_From_Range_Recent_Blocks(t *testing.T) { } func TestORM(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM o2 := th.ORM2 // Insert and read back a block. - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 10, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 10, time.Now(), 0)) b, err := o1.SelectBlockByHash(common.HexToHash("0x1234")) require.NoError(t, err) assert.Equal(t, b.BlockNumber, int64(10)) @@ -157,8 +162,8 @@ func TestORM(t *testing.T) { assert.Equal(t, b.EvmChainId.String(), th.ChainID.String()) // Insert blocks from a different chain - require.NoError(t, o2.InsertBlock(common.HexToHash("0x1234"), 11, time.Now())) - require.NoError(t, o2.InsertBlock(common.HexToHash("0x1235"), 12, time.Now())) + require.NoError(t, o2.InsertBlock(common.HexToHash("0x1234"), 11, time.Now(), 0)) + require.NoError(t, o2.InsertBlock(common.HexToHash("0x1235"), 12, time.Now(), 0)) b2, err := o2.SelectBlockByHash(common.HexToHash("0x1234")) require.NoError(t, err) assert.Equal(t, b2.BlockNumber, int64(11)) @@ -293,43 +298,43 @@ func TestORM(t *testing.T) { require.Equal(t, 1, len(logs)) assert.Equal(t, []byte("hello"), logs[0].Data) - logs, err = o1.SelectLogsByBlockRangeFilter(1, 1, common.HexToAddress("0x1234"), topic) + logs, err = o1.SelectLogs(1, 1, common.HexToAddress("0x1234"), topic) require.NoError(t, err) assert.Equal(t, 0, len(logs)) - logs, err = o1.SelectLogsByBlockRangeFilter(10, 10, common.HexToAddress("0x1234"), topic) + logs, err = o1.SelectLogs(10, 10, common.HexToAddress("0x1234"), topic) require.NoError(t, err) require.Equal(t, 1, len(logs)) // With no blocks, should be an error - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) // With block 10, only 0 confs should work - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 10, time.Now())) - log, err := o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 10, time.Now(), 0)) + log, err := o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) require.NoError(t, err) assert.Equal(t, int64(10), log.BlockNumber) - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 1) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 1) require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) // With block 12, anything <=2 should work require.NoError(t, o1.DeleteBlocksAfter(10)) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 11, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 12, time.Now())) - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 11, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 12, time.Now(), 0)) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 0) require.NoError(t, err) - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 1) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 1) require.NoError(t, err) - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 2) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 2) require.NoError(t, err) - _, err = o1.SelectLatestLogEventSigWithConfs(topic, common.HexToAddress("0x1234"), 3) + _, err = o1.SelectLatestLogByEventSigWithConfs(topic, common.HexToAddress("0x1234"), 3) require.Error(t, err) assert.True(t, errors.Is(err, sql.ErrNoRows)) // Required for confirmations to work - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 13, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 14, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1236"), 15, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 13, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 14, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1236"), 15, time.Now(), 0)) // Latest log for topic for addr "0x1234" is @ block 11 lgs, err := o1.SelectLatestLogEventSigsAddrsWithConfs(0 /* startBlock */, []common.Address{common.HexToAddress("0x1234")}, []common.Hash{topic}, 0) @@ -363,8 +368,8 @@ func TestORM(t *testing.T) { require.NoError(t, err) require.Equal(t, 2, len(lgs)) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1237"), 16, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1238"), 17, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1237"), 16, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1238"), 17, time.Now(), 0)) filter0 := logpoller.Filter{ Name: "permanent retention filter", @@ -423,7 +428,7 @@ func TestORM(t *testing.T) { require.Zero(t, len(logs)) } -func insertLogsTopicValueRange(t *testing.T, chainID *big.Int, o *logpoller.ORM, addr common.Address, blockNumber int, eventSig common.Hash, start, stop int) { +func insertLogsTopicValueRange(t *testing.T, chainID *big.Int, o *logpoller.DbORM, addr common.Address, blockNumber int, eventSig common.Hash, start, stop int) { var lgs []logpoller.Log for i := start; i <= stop; i++ { lgs = append(lgs, logpoller.Log{ @@ -442,11 +447,11 @@ func insertLogsTopicValueRange(t *testing.T, chainID *big.Int, o *logpoller.ORM, } func TestORM_IndexedLogs(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM eventSig := common.HexToHash("0x1599") addr := common.HexToAddress("0x1234") - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) insertLogsTopicValueRange(t, th.ChainID, o1, addr, 1, eventSig, 1, 3) insertLogsTopicValueRange(t, th.ChainID, o1, addr, 2, eventSig, 4, 4) // unconfirmed @@ -459,57 +464,57 @@ func TestORM_IndexedLogs(t *testing.T) { require.NoError(t, err) assert.Equal(t, 2, len(lgs)) - lgs, err = o1.SelectIndexedLogsByBlockRangeFilter(1, 1, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) + lgs, err = o1.SelectIndexedLogsByBlockRange(1, 1, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) - lgs, err = o1.SelectIndexedLogsByBlockRangeFilter(1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(2)}) + lgs, err = o1.SelectIndexedLogsByBlockRange(1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(2)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) - lgs, err = o1.SelectIndexedLogsByBlockRangeFilter(1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) + lgs, err = o1.SelectIndexedLogsByBlockRange(1, 2, addr, eventSig, 1, []common.Hash{logpoller.EvmWord(1)}) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) - _, err = o1.SelectIndexedLogsByBlockRangeFilter(1, 2, addr, eventSig, 0, []common.Hash{logpoller.EvmWord(1)}) + _, err = o1.SelectIndexedLogsByBlockRange(1, 2, addr, eventSig, 0, []common.Hash{logpoller.EvmWord(1)}) require.Error(t, err) assert.Contains(t, err.Error(), "invalid index for topic: 0") - _, err = o1.SelectIndexedLogsByBlockRangeFilter(1, 2, addr, eventSig, 4, []common.Hash{logpoller.EvmWord(1)}) + _, err = o1.SelectIndexedLogsByBlockRange(1, 2, addr, eventSig, 4, []common.Hash{logpoller.EvmWord(1)}) require.Error(t, err) assert.Contains(t, err.Error(), "invalid index for topic: 4") - lgs, err = o1.SelectIndexLogsTopicGreaterThan(addr, eventSig, 1, logpoller.EvmWord(2), 0) + lgs, err = o1.SelectIndexedLogsTopicGreaterThan(addr, eventSig, 1, logpoller.EvmWord(2), 0) require.NoError(t, err) assert.Equal(t, 2, len(lgs)) - lgs, err = o1.SelectIndexLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) + lgs, err = o1.SelectIndexedLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) assert.Equal(t, logpoller.EvmWord(3).Bytes(), lgs[0].GetTopics()[1].Bytes()) - lgs, err = o1.SelectIndexLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(1), logpoller.EvmWord(3), 0) + lgs, err = o1.SelectIndexedLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(1), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 3, len(lgs)) // Check confirmations work as expected. - require.NoError(t, o1.InsertBlock(common.HexToHash("0x2"), 2, time.Now())) - lgs, err = o1.SelectIndexLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(4), logpoller.EvmWord(4), 1) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x2"), 2, time.Now(), 0)) + lgs, err = o1.SelectIndexedLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(4), logpoller.EvmWord(4), 1) require.NoError(t, err) assert.Equal(t, 0, len(lgs)) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x3"), 3, time.Now())) - lgs, err = o1.SelectIndexLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(4), logpoller.EvmWord(4), 1) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x3"), 3, time.Now(), 0)) + lgs, err = o1.SelectIndexedLogsTopicRange(addr, eventSig, 1, logpoller.EvmWord(4), logpoller.EvmWord(4), 1) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) } func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { - th := SetupTH(t, 0, 3, 2) + th := SetupTH(t, false, 0, 3, 2, 1000) o1 := th.ORM eventSig := common.HexToHash("0x1599") txHash := common.HexToHash("0x1888") addr := common.HexToAddress("0x1234") - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) logs := []logpoller.Log{ { EvmChainId: utils.NewBig(th.ChainID), @@ -569,11 +574,11 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { } func TestORM_DataWords(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM eventSig := common.HexToHash("0x1599") addr := common.HexToAddress("0x1234") - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) require.NoError(t, o1.InsertLogs([]logpoller.Log{ { EvmChainId: utils.NewBig(th.ChainID), @@ -600,58 +605,43 @@ func TestORM_DataWords(t *testing.T) { }, })) // Outside range should fail. - lgs, err := o1.SelectDataWordRange(addr, eventSig, 0, logpoller.EvmWord(2), logpoller.EvmWord(2), 0) + lgs, err := o1.SelectLogsDataWordRange(addr, eventSig, 0, logpoller.EvmWord(2), logpoller.EvmWord(2), 0) require.NoError(t, err) assert.Equal(t, 0, len(lgs)) // Range including log should succeed - lgs, err = o1.SelectDataWordRange(addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(2), 0) + lgs, err = o1.SelectLogsDataWordRange(addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(2), 0) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) // Range only covering log should succeed - lgs, err = o1.SelectDataWordRange(addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(1), 0) + lgs, err = o1.SelectLogsDataWordRange(addr, eventSig, 0, logpoller.EvmWord(1), logpoller.EvmWord(1), 0) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) // Cannot query for unconfirmed second log. - lgs, err = o1.SelectDataWordRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) + lgs, err = o1.SelectLogsDataWordRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 0, len(lgs)) // Confirm it, then can query. - require.NoError(t, o1.InsertBlock(common.HexToHash("0x2"), 2, time.Now())) - lgs, err = o1.SelectDataWordRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x2"), 2, time.Now(), 0)) + lgs, err = o1.SelectLogsDataWordRange(addr, eventSig, 1, logpoller.EvmWord(3), logpoller.EvmWord(3), 0) require.NoError(t, err) assert.Equal(t, 1, len(lgs)) assert.Equal(t, lgs[0].Data, append(logpoller.EvmWord(2).Bytes(), logpoller.EvmWord(3).Bytes()...)) // Check greater than 1 yields both logs. - lgs, err = o1.SelectDataWordGreaterThan(addr, eventSig, 0, logpoller.EvmWord(1), 0) - require.NoError(t, err) - assert.Equal(t, 2, len(lgs)) - - // Unknown hash should an error - lgs, err = o1.SelectUntilBlockHashDataWordGreaterThan(addr, eventSig, 0, logpoller.EvmWord(1), common.HexToHash("0x3")) - require.Error(t, err) - assert.Equal(t, 0, len(lgs)) - - // 1 block should include first log - lgs, err = o1.SelectUntilBlockHashDataWordGreaterThan(addr, eventSig, 0, logpoller.EvmWord(1), common.HexToHash("0x1")) - require.NoError(t, err) - assert.Equal(t, 1, len(lgs)) - - // 2 block should include both - lgs, err = o1.SelectUntilBlockHashDataWordGreaterThan(addr, eventSig, 0, logpoller.EvmWord(1), common.HexToHash("0x2")) + lgs, err = o1.SelectLogsDataWordGreaterThan(addr, eventSig, 0, logpoller.EvmWord(1), 0) require.NoError(t, err) assert.Equal(t, 2, len(lgs)) } func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM // Insert logs on different topics, should be able to read them - // back using SelectLogsWithSigsByBlockRangeFilter and specifying + // back using SelectLogsWithSigs and specifying // said topics. topic := common.HexToHash("0x1599") topic2 := common.HexToHash("0x1600") @@ -727,7 +717,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { require.NoError(t, o1.InsertLogs(inputLogs)) startBlock, endBlock := int64(10), int64(15) - logs, err := o1.SelectLogsWithSigsByBlockRangeFilter(startBlock, endBlock, sourceAddr, []common.Hash{ + logs, err := o1.SelectLogsWithSigs(startBlock, endBlock, sourceAddr, []common.Hash{ topic, topic2, }) @@ -741,10 +731,10 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { } func TestORM_DeleteBlocksBefore(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) o1 := th.ORM - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 1, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 2, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1234"), 1, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1235"), 2, time.Now(), 0)) require.NoError(t, o1.DeleteBlocksBefore(1)) // 1 should be gone. _, err := o1.SelectBlockByNumber(1) @@ -753,8 +743,8 @@ func TestORM_DeleteBlocksBefore(t *testing.T) { require.NoError(t, err) assert.Equal(t, int64(2), b.BlockNumber) // Clear multiple - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1236"), 3, time.Now())) - require.NoError(t, o1.InsertBlock(common.HexToHash("0x1237"), 4, time.Now())) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1236"), 3, time.Now(), 0)) + require.NoError(t, o1.InsertBlock(common.HexToHash("0x1237"), 4, time.Now(), 0)) require.NoError(t, o1.DeleteBlocksBefore(3)) _, err = o1.SelectBlockByNumber(2) require.Equal(t, err, sql.ErrNoRows) @@ -764,7 +754,7 @@ func TestORM_DeleteBlocksBefore(t *testing.T) { func TestLogPoller_Logs(t *testing.T) { t.Parallel() - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) event1 := EmitterABI.Events["Log1"].ID event2 := EmitterABI.Events["Log2"].ID address1 := common.HexToAddress("0x2ab9a2Dc53736b361b72d900CdF9F78F9406fbbb") @@ -792,7 +782,7 @@ func TestLogPoller_Logs(t *testing.T) { assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[5].BlockHash.String()) // Filter by Address and topic - lgs, err = th.ORM.SelectLogsByBlockRangeFilter(1, 3, address1, event1) + lgs, err = th.ORM.SelectLogs(1, 3, address1, event1) require.NoError(t, err) require.Equal(t, 2, len(lgs)) assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000003", lgs[0].BlockHash.String()) @@ -802,7 +792,7 @@ func TestLogPoller_Logs(t *testing.T) { assert.Equal(t, address1, lgs[1].Address) // Filter by block - lgs, err = th.ORM.SelectLogsByBlockRangeFilter(2, 2, address2, event1) + lgs, err = th.ORM.SelectLogs(2, 2, address2, event1) require.NoError(t, err) require.Equal(t, 1, len(lgs)) assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000004", lgs[0].BlockHash.String()) @@ -812,7 +802,7 @@ func TestLogPoller_Logs(t *testing.T) { } func BenchmarkLogs(b *testing.B) { - th := SetupTH(b, 2, 3, 2) + th := SetupTH(b, false, 2, 3, 2, 1000) o := th.ORM var lgs []logpoller.Log addr := common.HexToAddress("0x1234") @@ -832,13 +822,13 @@ func BenchmarkLogs(b *testing.B) { require.NoError(b, o.InsertLogs(lgs)) b.ResetTimer() for n := 0; n < b.N; n++ { - _, err := o.SelectDataWordRange(addr, EmitterABI.Events["Log1"].ID, 0, logpoller.EvmWord(8000), logpoller.EvmWord(8002), 0) + _, err := o.SelectLogsDataWordRange(addr, EmitterABI.Events["Log1"].ID, 0, logpoller.EvmWord(8000), logpoller.EvmWord(8002), 0) require.NoError(b, err) } } func TestSelectLogsWithSigsExcluding(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) orm := th.ORM addressA := common.HexToAddress("0x11111") addressB := common.HexToAddress("0x22222") @@ -881,7 +871,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-B1"), }, })) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x1"), 1, time.Now())) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) //Get any requestSigA from addressA that do not have a equivalent responseSigA logs, err := orm.SelectIndexedLogsWithSigsExcluding(requestSigA, responseSigA, 1, addressA, 0, 3, 0) @@ -910,7 +900,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("responseID-A1"), }, })) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x2"), 2, time.Now())) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x2"), 2, time.Now(), 0)) //Should return nothing as requestID-A1 has been fulfilled logs, err = orm.SelectIndexedLogsWithSigsExcluding(requestSigA, responseSigA, 1, addressA, 0, 3, 0) @@ -961,7 +951,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-C3"), }, })) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x3"), 3, time.Now())) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x3"), 3, time.Now(), 0)) //Get all unfulfilled requests from addressC, match on topic index 3 logs, err = orm.SelectIndexedLogsWithSigsExcluding(requestSigB, responseSigB, 3, addressC, 0, 4, 0) @@ -1021,13 +1011,13 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { require.NoError(t, err) require.Len(t, logs, 0) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x4"), 4, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x5"), 5, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x6"), 6, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x7"), 7, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x8"), 8, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x9"), 9, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x10"), 10, time.Now())) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x4"), 4, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x5"), 5, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x6"), 6, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x7"), 7, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x8"), 8, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x9"), 9, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x10"), 10, time.Now(), 0)) //Fulfill requestID-C3 require.NoError(t, orm.InsertLogs([]logpoller.Log{ @@ -1057,9 +1047,9 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { require.Equal(t, logs[0].Data, []byte("requestID-C1")) //Insert 3 more blocks so that the requestID-C1 has enough confirmations - require.NoError(t, orm.InsertBlock(common.HexToHash("0x11"), 11, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x12"), 12, time.Now())) - require.NoError(t, orm.InsertBlock(common.HexToHash("0x13"), 13, time.Now())) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x11"), 11, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x12"), 12, time.Now(), 0)) + require.NoError(t, orm.InsertBlock(common.HexToHash("0x13"), 13, time.Now(), 0)) logs, err = orm.SelectIndexedLogsWithSigsExcluding(requestSigB, responseSigB, 3, addressC, 0, 10, 0) require.NoError(t, err) @@ -1084,25 +1074,25 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { } func TestSelectLatestBlockNumberEventSigsAddrsWithConfs(t *testing.T) { - th := SetupTH(t, 2, 3, 2) + th := SetupTH(t, false, 2, 3, 2, 1000) event1 := EmitterABI.Events["Log1"].ID event2 := EmitterABI.Events["Log2"].ID - address1 := common.HexToAddress("0xA") - address2 := common.HexToAddress("0xB") + address1 := utils.RandomAddress() + address2 := utils.RandomAddress() require.NoError(t, th.ORM.InsertLogs([]logpoller.Log{ - GenLog(th.ChainID, 1, 1, "0x1", event1[:], address1), - GenLog(th.ChainID, 2, 1, "0x2", event2[:], address2), - GenLog(th.ChainID, 2, 2, "0x4", event2[:], address2), - GenLog(th.ChainID, 2, 3, "0x6", event2[:], address2), + GenLog(th.ChainID, 1, 1, utils.RandomAddress().String(), event1[:], address1), + GenLog(th.ChainID, 2, 1, utils.RandomAddress().String(), event2[:], address2), + GenLog(th.ChainID, 2, 2, utils.RandomAddress().String(), event2[:], address2), + GenLog(th.ChainID, 2, 3, utils.RandomAddress().String(), event2[:], address2), })) - require.NoError(t, th.ORM.InsertBlock(common.HexToHash("0x1"), 3, time.Now())) + require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 3, time.Now(), 1)) tests := []struct { name string events []common.Hash addrs []common.Address - confs int + confs logpoller.Confirmations fromBlock int64 expectedBlockNumber int64 }{ @@ -1130,6 +1120,14 @@ func TestSelectLatestBlockNumberEventSigsAddrsWithConfs(t *testing.T) { fromBlock: 0, expectedBlockNumber: 1, }, + { + name: "only finalized log is picked", + events: []common.Hash{event1, event2}, + addrs: []common.Address{address1, address2}, + confs: logpoller.Finalized, + fromBlock: 0, + expectedBlockNumber: 1, + }, { name: "picks max block from two events", events: []common.Hash{event1, event2}, @@ -1165,9 +1163,141 @@ func TestSelectLatestBlockNumberEventSigsAddrsWithConfs(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - blockNumber, err := th.ORM.SelectLatestBlockNumberEventSigsAddrsWithConfs(tt.fromBlock, tt.events, tt.addrs, tt.confs) + blockNumber, err := th.ORM.SelectLatestBlockByEventSigsAddrsWithConfs(tt.fromBlock, tt.events, tt.addrs, tt.confs) require.NoError(t, err) assert.Equal(t, tt.expectedBlockNumber, blockNumber) }) } } + +func TestSelectLogsCreatedAfter(t *testing.T) { + th := SetupTH(t, false, 2, 3, 2, 1000) + event := EmitterABI.Events["Log1"].ID + address := utils.RandomAddress() + + block1ts := time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC) + block2ts := time.Date(2020, 1, 1, 12, 12, 12, 0, time.UTC) + block3ts := time.Date(2030, 1, 1, 12, 12, 12, 0, time.UTC) + + require.NoError(t, th.ORM.InsertLogs([]logpoller.Log{ + GenLogWithTimestamp(th.ChainID, 1, 1, utils.RandomAddress().String(), event[:], address, block1ts), + GenLogWithTimestamp(th.ChainID, 1, 2, utils.RandomAddress().String(), event[:], address, block2ts), + GenLogWithTimestamp(th.ChainID, 2, 2, utils.RandomAddress().String(), event[:], address, block2ts), + GenLogWithTimestamp(th.ChainID, 1, 3, utils.RandomAddress().String(), event[:], address, block3ts), + })) + require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 1, block1ts, 0)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 2, block2ts, 1)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 3, block3ts, 2)) + + type expectedLog struct { + block int64 + log int64 + } + + tests := []struct { + name string + confs logpoller.Confirmations + after time.Time + expectedLogs []expectedLog + }{ + { + name: "picks logs after block 1", + confs: 0, + after: block1ts, + expectedLogs: []expectedLog{ + {block: 2, log: 1}, + {block: 2, log: 2}, + {block: 3, log: 1}, + }, + }, + { + name: "skips blocks with not enough confirmations", + confs: 1, + after: block1ts, + expectedLogs: []expectedLog{ + {block: 2, log: 1}, + {block: 2, log: 2}, + }, + }, + { + name: "limits number of blocks by block_timestamp", + confs: 0, + after: block2ts, + expectedLogs: []expectedLog{ + {block: 3, log: 1}, + }, + }, + { + name: "returns empty dataset for future timestamp", + confs: 0, + after: block3ts, + expectedLogs: []expectedLog{}, + }, + { + name: "returns empty dataset when too many confirmations are required", + confs: 3, + after: block1ts, + expectedLogs: []expectedLog{}, + }, + { + name: "returns only finalized log", + confs: logpoller.Finalized, + after: block1ts, + expectedLogs: []expectedLog{ + {block: 2, log: 1}, + {block: 2, log: 2}, + }, + }, + } + for _, tt := range tests { + t.Run("SelectLogsCreatedAfter"+tt.name, func(t *testing.T) { + logs, err := th.ORM.SelectLogsCreatedAfter(address, event, tt.after, tt.confs) + require.NoError(t, err) + require.Len(t, logs, len(tt.expectedLogs)) + + for i, log := range logs { + require.Equal(t, tt.expectedLogs[i].block, log.BlockNumber) + require.Equal(t, tt.expectedLogs[i].log, log.LogIndex) + } + }) + + t.Run("SelectIndexedLogsCreatedAfter"+tt.name, func(t *testing.T) { + logs, err := th.ORM.SelectIndexedLogsCreatedAfter(address, event, 1, []common.Hash{event}, tt.after, tt.confs) + require.NoError(t, err) + require.Len(t, logs, len(tt.expectedLogs)) + + for i, log := range logs { + require.Equal(t, tt.expectedLogs[i].block, log.BlockNumber) + require.Equal(t, tt.expectedLogs[i].log, log.LogIndex) + } + }) + } +} + +func TestNestedLogPollerBlocksQuery(t *testing.T) { + th := SetupTH(t, false, 2, 3, 2, 1000) + event := EmitterABI.Events["Log1"].ID + address := utils.RandomAddress() + + require.NoError(t, th.ORM.InsertLogs([]logpoller.Log{ + GenLog(th.ChainID, 1, 8, utils.RandomAddress().String(), event[:], address), + })) + + // Empty logs when block are not persisted + logs, err := th.ORM.SelectIndexedLogs(address, event, 1, []common.Hash{event}, logpoller.Unconfirmed) + require.NoError(t, err) + require.Len(t, logs, 0) + + // Persist block + require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 10, time.Now(), 0)) + + // Check if query actually works well with provided dataset + logs, err = th.ORM.SelectIndexedLogs(address, event, 1, []common.Hash{event}, logpoller.Unconfirmed) + require.NoError(t, err) + require.Len(t, logs, 1) + + // Empty logs when number of confirmations is too deep + logs, err = th.ORM.SelectIndexedLogs(address, event, 1, []common.Hash{event}, logpoller.Confirmations(4)) + require.NoError(t, err) + require.Len(t, logs, 0) +} diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go new file mode 100644 index 00000000000..7443a860a85 --- /dev/null +++ b/core/chains/evm/logpoller/query.go @@ -0,0 +1,132 @@ +package logpoller + +import ( + "errors" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type bytesProducer interface { + Bytes() []byte +} + +func concatBytes[T bytesProducer](byteSlice []T) pq.ByteaArray { + var output [][]byte + for _, b := range byteSlice { + output = append(output, b.Bytes()) + } + return output +} + +// queryArgs is a helper for building the arguments to a postgres query created by DbORM +// Besides the convenience methods, it also keeps track of arguments validation and sanitization. +type queryArgs struct { + args map[string]interface{} + err []error +} + +func newQueryArgs(chainId *big.Int) *queryArgs { + return &queryArgs{ + args: map[string]interface{}{ + "evm_chain_id": utils.NewBig(chainId), + }, + err: []error{}, + } +} + +func newQueryArgsForEvent(chainId *big.Int, address common.Address, eventSig common.Hash) *queryArgs { + return newQueryArgs(chainId). + withAddress(address). + withEventSig(eventSig) +} + +func (q *queryArgs) withEventSig(eventSig common.Hash) *queryArgs { + return q.withCustomHashArg("event_sig", eventSig) +} + +func (q *queryArgs) withEventSigArray(eventSigs []common.Hash) *queryArgs { + return q.withCustomArg("event_sig_array", concatBytes(eventSigs)) +} + +func (q *queryArgs) withAddress(address common.Address) *queryArgs { + return q.withCustomArg("address", address) +} + +func (q *queryArgs) withAddressArray(addresses []common.Address) *queryArgs { + return q.withCustomArg("address_array", concatBytes(addresses)) +} + +func (q *queryArgs) withStartBlock(startBlock int64) *queryArgs { + return q.withCustomArg("start_block", startBlock) +} + +func (q *queryArgs) withEndBlock(endBlock int64) *queryArgs { + return q.withCustomArg("end_block", endBlock) +} + +func (q *queryArgs) withWordIndex(wordIndex int) *queryArgs { + return q.withCustomArg("word_index", wordIndex) +} + +func (q *queryArgs) withWordValueMin(wordValueMin common.Hash) *queryArgs { + return q.withCustomHashArg("word_value_min", wordValueMin) +} + +func (q *queryArgs) withWordValueMax(wordValueMax common.Hash) *queryArgs { + return q.withCustomHashArg("word_value_max", wordValueMax) +} + +func (q *queryArgs) withConfs(confs Confirmations) *queryArgs { + return q.withCustomArg("confs", confs) +} + +func (q *queryArgs) withTopicIndex(index int) *queryArgs { + // Only topicIndex 1 through 3 is valid. 0 is the event sig and only 4 total topics are allowed + if !(index == 1 || index == 2 || index == 3) { + q.err = append(q.err, fmt.Errorf("invalid index for topic: %d", index)) + } + // Add 1 since postgresql arrays are 1-indexed. + return q.withCustomArg("topic_index", index+1) +} + +func (q *queryArgs) withTopicValueMin(valueMin common.Hash) *queryArgs { + return q.withCustomHashArg("topic_value_min", valueMin) +} + +func (q *queryArgs) withTopicValueMax(valueMax common.Hash) *queryArgs { + return q.withCustomHashArg("topic_value_max", valueMax) +} + +func (q *queryArgs) withTopicValues(values []common.Hash) *queryArgs { + return q.withCustomArg("topic_values", concatBytes(values)) +} + +func (q *queryArgs) withBlockTimestampAfter(after time.Time) *queryArgs { + return q.withCustomArg("block_timestamp_after", after) +} + +func (q *queryArgs) withTxHash(hash common.Hash) *queryArgs { + return q.withCustomHashArg("tx_hash", hash) +} + +func (q *queryArgs) withCustomHashArg(name string, arg common.Hash) *queryArgs { + return q.withCustomArg(name, arg.Bytes()) +} + +func (q *queryArgs) withCustomArg(name string, arg any) *queryArgs { + q.args[name] = arg + return q +} + +func (q *queryArgs) toArgs() (map[string]interface{}, error) { + if len(q.err) > 0 { + return nil, errors.Join(q.err...) + } + return q.args, nil +} diff --git a/core/chains/evm/logpoller/query_test.go b/core/chains/evm/logpoller/query_test.go new file mode 100644 index 00000000000..e38aeb05819 --- /dev/null +++ b/core/chains/evm/logpoller/query_test.go @@ -0,0 +1,82 @@ +package logpoller + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +func Test_QueryArgs(t *testing.T) { + tests := []struct { + name string + queryArgs *queryArgs + want map[string]interface{} + wantErr bool + }{ + { + name: "valid arguments", + queryArgs: newQueryArgs(big.NewInt(20)).withAddress(utils.ZeroAddress), + want: map[string]interface{}{ + "evm_chain_id": utils.NewBigI(20), + "address": utils.ZeroAddress, + }, + }, + { + name: "invalid topic index", + queryArgs: newQueryArgs(big.NewInt(20)).withTopicIndex(0), + wantErr: true, + }, + { + name: "custom argument", + queryArgs: newEmptyArgs().withCustomArg("arg", "value"), + want: map[string]interface{}{ + "arg": "value", + }, + }, + { + name: "hash converted to bytes", + queryArgs: newEmptyArgs().withCustomHashArg("hash", common.Hash{}), + want: map[string]interface{}{ + "hash": make([]byte, 32), + }, + }, + { + name: "hash array converted to bytes array", + queryArgs: newEmptyArgs().withEventSigArray([]common.Hash{{}, {}}), + want: map[string]interface{}{ + "event_sig_array": pq.ByteaArray{make([]byte, 32), make([]byte, 32)}, + }, + }, + { + name: "topic index incremented", + queryArgs: newEmptyArgs().withTopicIndex(2), + want: map[string]interface{}{ + "topic_index": 3, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + args, err := tt.queryArgs.toArgs() + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.want, args) + } + }) + } +} + +func newEmptyArgs() *queryArgs { + return &queryArgs{ + args: map[string]interface{}{}, + err: []error{}, + } +} diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index daf1ec55275..2a5e66bbc02 100644 --- a/core/chains/evm/mocks/balance_monitor.go +++ b/core/chains/evm/mocks/balance_monitor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -111,13 +111,12 @@ func (_m *BalanceMonitor) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewBalanceMonitor interface { +// NewBalanceMonitor creates a new instance of BalanceMonitor. 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 NewBalanceMonitor(t interface { mock.TestingT Cleanup(func()) -} - -// NewBalanceMonitor creates a new instance of BalanceMonitor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBalanceMonitor(t mockConstructorTestingTNewBalanceMonitor) *BalanceMonitor { +}) *BalanceMonitor { mock := &BalanceMonitor{} mock.Mock.Test(t) diff --git a/core/chains/evm/mocks/chain.go b/core/chains/evm/mocks/chain.go index bf4d1581e22..f0f202b0938 100644 --- a/core/chains/evm/mocks/chain.go +++ b/core/chains/evm/mocks/chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -364,13 +364,12 @@ func (_m *Chain) TxManager() txmgr.TxManager[*big.Int, *evmtypes.Head, common.Ad return r0 } -type mockConstructorTestingTNewChain interface { +// NewChain creates a new instance of Chain. 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 NewChain(t interface { mock.TestingT Cleanup(func()) -} - -// NewChain creates a new instance of Chain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewChain(t mockConstructorTestingTNewChain) *Chain { +}) *Chain { mock := &Chain{} mock.Mock.Test(t) diff --git a/core/chains/evm/mocks/legacy_chain_container.go b/core/chains/evm/mocks/legacy_chain_container.go index d8dfa209a08..9180a8a2fc5 100644 --- a/core/chains/evm/mocks/legacy_chain_container.go +++ b/core/chains/evm/mocks/legacy_chain_container.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -118,13 +118,12 @@ func (_m *LegacyChainContainer) Slice() []evm.Chain { return r0 } -type mockConstructorTestingTNewLegacyChainContainer interface { +// NewLegacyChainContainer creates a new instance of LegacyChainContainer. 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 NewLegacyChainContainer(t interface { mock.TestingT Cleanup(func()) -} - -// NewLegacyChainContainer creates a new instance of LegacyChainContainer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLegacyChainContainer(t mockConstructorTestingTNewLegacyChainContainer) *LegacyChainContainer { +}) *LegacyChainContainer { mock := &LegacyChainContainer{} mock.Mock.Test(t) diff --git a/core/chains/evm/mocks/node.go b/core/chains/evm/mocks/node.go index 9470bd39387..85db2e0ca0f 100644 --- a/core/chains/evm/mocks/node.go +++ b/core/chains/evm/mocks/node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -591,6 +591,20 @@ func (_m *Node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, return r0, r1 } +// SubscribersCount provides a mock function with given fields: +func (_m *Node) SubscribersCount() int32 { + ret := _m.Called() + + var r0 int32 + if rf, ok := ret.Get(0).(func() int32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int32) + } + + return r0 +} + // SuggestGasPrice provides a mock function with given fields: ctx func (_m *Node) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) @@ -695,13 +709,17 @@ func (_m *Node) TransactionReceipt(ctx context.Context, txHash common.Hash) (*ty return r0, r1 } -type mockConstructorTestingTNewNode interface { - mock.TestingT - Cleanup(func()) +// UnsubscribeAllExceptAliveLoop provides a mock function with given fields: +func (_m *Node) UnsubscribeAllExceptAliveLoop() { + _m.Called() } // NewNode creates a new instance of Node. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewNode(t mockConstructorTestingTNewNode) *Node { +// The first argument is typically a *testing.T value. +func NewNode(t interface { + mock.TestingT + Cleanup(func()) +}) *Node { mock := &Node{} mock.Mock.Test(t) diff --git a/core/chains/evm/mocks/send_only_node.go b/core/chains/evm/mocks/send_only_node.go index 210d103dea2..c836399a8ba 100644 --- a/core/chains/evm/mocks/send_only_node.go +++ b/core/chains/evm/mocks/send_only_node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -134,13 +134,12 @@ func (_m *SendOnlyNode) String() string { return r0 } -type mockConstructorTestingTNewSendOnlyNode interface { +// NewSendOnlyNode creates a new instance of SendOnlyNode. 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 NewSendOnlyNode(t interface { mock.TestingT Cleanup(func()) -} - -// NewSendOnlyNode creates a new instance of SendOnlyNode. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSendOnlyNode(t mockConstructorTestingTNewSendOnlyNode) *SendOnlyNode { +}) *SendOnlyNode { mock := &SendOnlyNode{} mock.Mock.Test(t) diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index 8dbd4ed8507..94434b733e6 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -47,12 +47,14 @@ type ( NullBalanceMonitor struct{} ) +var _ BalanceMonitor = (*balanceMonitor)(nil) + // NewBalanceMonitor returns a new balanceMonitor -func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, logger logger.Logger) BalanceMonitor { +func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, logger logger.Logger) *balanceMonitor { chainId := ethClient.ConfiguredChainID() bm := &balanceMonitor{ utils.StartStopOnce{}, - logger, + logger.Named("BalanceMonitor"), ethClient, chainId, chainId.String(), @@ -89,7 +91,7 @@ func (bm *balanceMonitor) Name() string { } func (bm *balanceMonitor) HealthReport() map[string]error { - return map[string]error{bm.Name(): bm.StartStopOnce.Healthy()} + return map[string]error{bm.Name(): bm.Healthy()} } // OnNewLongestChain checks the balance for each key diff --git a/core/chains/evm/monitor/balance_helpers_test.go b/core/chains/evm/monitor/balance_helpers_test.go new file mode 100644 index 00000000000..624aa69f061 --- /dev/null +++ b/core/chains/evm/monitor/balance_helpers_test.go @@ -0,0 +1,7 @@ +package monitor + +func (bm *balanceMonitor) WorkDone() <-chan struct{} { + return bm.sleeperTask.(interface { + WorkDone() <-chan struct{} + }).WorkDone() +} diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index c908c395671..dbb2003b695 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -40,8 +40,8 @@ func TestBalanceMonitor_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -69,7 +69,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -89,7 +89,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -119,7 +119,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) defer func() { assert.NoError(t, bm.Close()) }() @@ -146,8 +146,8 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := newEthClientMock(t) - _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) + _, k1Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.TestLogger(t)) k0bal := big.NewInt(42) @@ -169,12 +169,9 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { // Do the thing bm.OnNewLongestChain(testutils.Context(t), head) - gomega.NewWithT(t).Eventually(func() *big.Int { - return bm.GetEthBalance(k0Addr).ToInt() - }).Should(gomega.Equal(k0bal)) - gomega.NewWithT(t).Eventually(func() *big.Int { - return bm.GetEthBalance(k1Addr).ToInt() - }).Should(gomega.Equal(k1bal)) + <-bm.WorkDone() + assert.Equal(t, k0bal, bm.GetEthBalance(k0Addr).ToInt()) + assert.Equal(t, k1bal, bm.GetEthBalance(k1Addr).ToInt()) // Do it again k0bal2 := big.NewInt(142) @@ -187,12 +184,9 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { bm.OnNewLongestChain(testutils.Context(t), head) - gomega.NewWithT(t).Eventually(func() *big.Int { - return bm.GetEthBalance(k0Addr).ToInt() - }).Should(gomega.Equal(k0bal2)) - gomega.NewWithT(t).Eventually(func() *big.Int { - return bm.GetEthBalance(k1Addr).ToInt() - }).Should(gomega.Equal(k1bal2)) + <-bm.WorkDone() + assert.Equal(t, k0bal2, bm.GetEthBalance(k0Addr).ToInt()) + assert.Equal(t, k1bal2, bm.GetEthBalance(k1Addr).ToInt()) }) } @@ -203,7 +197,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := newEthClientMock(t) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index e1133e8ef21..6f9308548b3 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -32,6 +32,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -69,7 +70,7 @@ func NewTestEthBroadcaster( ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, keyStore) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eb, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) // Mark instance as test @@ -89,10 +90,10 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) - + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) eb := txmgr.NewEvmBroadcaster( txStore, txmgr.NewEvmTxmClient(ethClient), @@ -145,12 +146,15 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") @@ -170,7 +174,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }) t.Run("eth_txes exist for a different from address", func(t *testing.T) { - _, otherAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) cltest.MustCreateUnstartedTx(t, txStore, otherAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) assert.NoError(t, err) @@ -351,11 +354,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(rnd + 2) }) evmcfg = evmtest.NewChainScopedConfig(t, cfg) + ethClient.On("PendingNonceAt", mock.Anything, otherAddress).Return(uint64(1), nil).Once() eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(3) && tx.Value().Cmp(big.NewInt(242)) == 0 + return tx.Nonce() == uint64(343) && tx.Value().Cmp(big.NewInt(242)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(242)), &cltest.FixtureChainID) @@ -374,7 +378,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { require.NotNil(t, etx.FromAddress) assert.Equal(t, fromAddress, etx.FromAddress) require.NotNil(t, etx.Sequence) - assert.Equal(t, evmtypes.Nonce(3), *etx.Sequence) + assert.Equal(t, evmtypes.Nonce(343), *etx.Sequence) assert.NotNil(t, etx.BroadcastAt) assert.NotNil(t, etx.InitialBroadcastAt) assert.Len(t, etx.TxAttempts, 1) @@ -406,7 +410,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { }, } ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(4) && tx.Value().Cmp(big.NewInt(442)) == 0 + return tx.Nonce() == uint64(344) && tx.Value().Cmp(big.NewInt(442)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { if fmt.Sprintf("%s", callarg["value"]) == "0x1ba" { // 442 @@ -439,7 +443,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { t.Run("with unknown error, sends tx as normal", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(5) && tx.Value().Cmp(big.NewInt(542)) == 0 + return tx.Nonce() == uint64(345) && tx.Value().Cmp(big.NewInt(542)) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() ethClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { return fmt.Sprintf("%s", callarg["value"]) == "0x21e" // 542 @@ -493,12 +497,12 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &testCheckerFactory{} - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) checker := txmgr.TransmitCheckerSpec{ @@ -573,12 +577,15 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testing.T) { // non-transactional DB needed because we deliberately test for FK violation cfg, db := heavyweight.FullTestDBV2(t, "eth_broadcaster_optimistic_locking", nil) + eventBroadcaster := cltest.NewEventBroadcaster(t, cfg.Database().URL()) + require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ccfg := evmtest.NewChainScopedConfig(t, cfg) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -588,8 +595,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, ccfg.EVM().GasEstimator().PriceMaxKey(fromAddress)).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint32(500), nil).Run(func(_ mock.Arguments) { close(chStartEstimate) <-chBlock - }) - + }).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil) eb := txmgr.NewEvmBroadcaster( txStore, txmgr.NewEvmTxmClient(ethClient), @@ -598,7 +605,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ccfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, - &pg.NullEventBroadcaster{}, + eventBroadcaster, txBuilder, nil, logger.TestLogger(t), @@ -607,6 +614,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ) eb.XXXTestDisableUnstartedTxAutoProcessing() + // Start instance of broadcaster + require.NoError(t, eb.Start(testutils.Context(t))) + t.Cleanup(func() { assert.NoError(t, eb.Close()) }) + cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) go func() { @@ -619,7 +630,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi // Simulate a "PruneQueue" call assert.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE state = 'unstarted'`))) - close(chBlock) }() @@ -640,12 +650,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -687,7 +697,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) firstInProgress := txmgr.Tx{ FromAddress: fromAddress, @@ -722,10 +732,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved @@ -760,15 +770,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -798,15 +806,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -835,15 +841,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -874,15 +878,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -911,7 +913,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, nextNonce) + _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // Configured gas price changed @@ -920,12 +922,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - // Crashed right after we commit the database transaction that saved - // the nonce to the eth_tx so keys.next_nonce has not been - // incremented yet + // Crashed right after we commit the database transaction that saved the nonce to the eth_tx inProgressEthTx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, firstNonce, fromAddress) require.Len(t, inProgressEthTx.TxAttempts, 1) attempt := inProgressEthTx.TxAttempts[0] @@ -960,8 +960,8 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { }) } -func getLocalNextNonce(t *testing.T, kst keystore.Eth, fromAddress gethCommon.Address) uint64 { - n, err := kst.NextSequence(fromAddress, &cltest.FixtureChainID) +func getLocalNextNonce(t *testing.T, eb *txmgr.Broadcaster, fromAddress gethCommon.Address) uint64 { + n, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) require.NotNil(t, n) return uint64(n) @@ -971,7 +971,6 @@ func getLocalNextNonce(t *testing.T, kst keystore.Eth, fromAddress gethCommon.Ad // This in order to more deeply test ProcessUnstartedEthTxs over // multiple runs with previous errors in the database. func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { - var err error toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") value := big.Int(assets.NewEthValue(142)) gasLimit := uint32(242) @@ -982,11 +981,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) @@ -999,11 +998,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(clienttypes.Successful, errors.New("replacement transaction underpriced")).Once() // Do the thing - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check that the transaction was saved correctly with its attempt // We assume success and hand off to eth confirmer to eventually mark it as failed @@ -1021,7 +1018,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Len(t, etx1.TxAttempts, 1) // Check that the local nonce was incremented by one - finalNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + finalNextNonce := getLocalNextNonce(t, eb, fromAddress) require.NoError(t, err) require.NotNil(t, finalNextNonce) require.Equal(t, int64(1), int64(finalNextNonce)) @@ -1029,7 +1026,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client returns an error in the fatal errors category", func(t *testing.T) { fatalErrorExample := "exceeds block gas limit" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) t.Run("without callback", func(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1037,11 +1034,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(clienttypes.Fatal, errors.New(fatalErrorExample)).Once() - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check it was saved correctly with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1055,12 +1050,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Len(t, etx.TxAttempts, 0) // Check that the key had its nonce reset - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce evmtypes.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be - require.Equal(t, int64(localNextNonce), nonce) + require.Equal(t, int64(localNextNonce), int64(nonce)) }) @@ -1125,12 +1120,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { lggr := logger.TestLogger(t) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) - eb = txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + localNextNonce = getLocalNextNonce(t, eb, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) + require.NoError(t, err) + retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) }) }) }) @@ -1140,7 +1136,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("geth Client fails with error indicating that the transaction was too expensive", func(t *testing.T) { TxFeeExceedsCapError := "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1149,15 +1145,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // of multiple RPC nodes, it is possible that it can be accepted by // another node even if the primary one returns "exceeds the configured // cap" - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - require.Error(t, err) - assert.Contains(t, err.Error(), "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)") - assert.Contains(t, err.Error(), "error while sending transaction") - assert.True(t, retryable) - } + retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + require.Error(t, err) + assert.Contains(t, err.Error(), "tx fee (1.10 ether) exceeds the configured cap (1.00 ether)") + assert.Contains(t, err.Error(), "error while sending transaction") + assert.True(t, retryable) // Check it was saved with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1172,21 +1165,19 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { assert.Equal(t, txmgrtypes.TxAttemptInProgress, attempt.State) // Check that the key had its nonce reset - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce evmtypes.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) // Saved NextNonce must be the same as before because this transaction // was not accepted by the eth node and never can be - require.Equal(t, int64(localNextNonce), nonce) + require.Equal(t, int64(localNextNonce), int64(nonce)) // On the second try, the tx has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check it was saved with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1203,13 +1194,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was not accepted into mempool", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == localNextNonce + return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is the same as localNextNonce, implying that this sent transaction has not been accepted - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1235,11 +1226,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(clienttypes.Successful, nil).Once() - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check it was saved correctly with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1257,10 +1246,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth client call fails with an unexpected random error, and the nonce check also subsequently fails", func(t *testing.T) { retryableErrorExample := "some unknown error" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == localNextNonce + return tx.Nonce() == uint64(localNextNonce) }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() @@ -1289,11 +1278,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(clienttypes.Successful, nil).Once() - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err = eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check it was saved correctly with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1311,13 +1298,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth Client call fails with an unexpected random error, and transaction was accepted into mempool", func(t *testing.T) { retryableErrorExample := "some strange RPC returns an unexpected thing" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce }), fromAddress).Return(clienttypes.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is one higher than localNextNonce, implying that despite the error, this sent transaction has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1343,7 +1330,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1362,11 +1349,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(clienttypes.Successful, nil).Once() // Do the thing - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - require.NoError(t, err) - assert.False(t, retryable) - } + retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + require.NoError(t, err) + assert.False(t, retryable) // Check it was saved correctly with its attempt etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1393,7 +1378,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("failed to reach node for some reason", func(t *testing.T) { failedToReachNodeError := context.DeadlineExceeded - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1422,7 +1407,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // This happens if parity is rejecting transactions that are not priced high enough to even get into the mempool at all // It should pretend it was accepted into the mempool and hand off to ethConfirmer to bump gas as normal temporarilyUnderpricedError := "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee." - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) // Re-use the previously unfinished transaction, no need to insert new @@ -1431,11 +1416,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { }), fromAddress).Return(clienttypes.Successful, errors.New(temporarilyUnderpricedError)).Once() // Do the thing - { - retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) - assert.NoError(t, err) - assert.False(t, retryable) - } + retryable, err := eb.ProcessUnstartedTxs(testutils.Context(t), fromAddress) + assert.NoError(t, err) + assert.False(t, retryable) // Check it was saved correctly with its attempt etx, err := txStore.FindTxWithAttempts(etxUnfinished.ID) @@ -1455,7 +1438,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) // In this scenario the node operator REALLY fucked up and set the bump // to zero (even though that should not be possible due to config // validation) @@ -1463,6 +1446,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1483,7 +1467,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Run("eth tx is left in progress if eth node returns insufficient eth", func(t *testing.T) { insufficientEthError := "insufficient funds for transfer" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce @@ -1512,7 +1496,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM evm.txes`) t.Run("eth tx is left in progress if nonce is too high", func(t *testing.T) { - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) nonceGapError := "NonceGap, Future nonce. Expected nonce: " + strconv.FormatUint(localNextNonce, 10) etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1553,10 +1537,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce = getLocalNextNonce(t, eb, fromAddress) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(1)) == 0 }), fromAddress).Return(clienttypes.Underpriced, errors.New(underpricedError)).Once() @@ -1575,7 +1561,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) + localNextNonce := getLocalNextNonce(t, eb, fromAddress) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // Check gas tip cap verification @@ -1583,6 +1569,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) })) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) @@ -1596,6 +1583,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault })) + localNextNonce = getLocalNextNonce(t, eb, fromAddress) eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) // Second was underpriced but above minimum @@ -1640,11 +1628,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { kst := ksmocks.NewEth(t) addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil) - next, err := realKeystore.Eth().NextSequence(fromAddress, testutils.FixtureChainID) - require.NoError(t, err) - kst.On("NextSequence", fromAddress, testutils.FixtureChainID, mock.Anything).Return(next, nil).Once() + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) + _, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) t.Run("tx signing fails", func(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1670,21 +1658,27 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { assert.Len(t, etx.TxAttempts, 0) // Check that the key did not have its nonce incremented - var nonce int64 - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + var nonce types.Nonce + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) - require.Equal(t, int64(localNonce), nonce) + require.Equal(t, int64(localNonce), int64(nonce)) }) } func TestEthBroadcaster_GetNextNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + fromAddress := testutils.NewAddress() + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - keyState, _ := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - nonce := getLocalNextNonce(t, ethKeyStore, keyState.Address.Address()) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) + nonce := getLocalNextNonce(t, eb, fromAddress) require.NotNil(t, nonce) assert.Equal(t, int64(0), int64(nonce)) } @@ -1692,20 +1686,25 @@ func TestEthBroadcaster_GetNextNonce(t *testing.T) { func TestEthBroadcaster_IncrementNextNonce(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + kst := ksmocks.NewEth(t) + fromAddress := testutils.NewAddress() + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - keyState, _ := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - // Cannot increment if supplied nonce doesn't match existing - require.Error(t, ethKeyStore.IncrementNextSequence(keyState.Address.Address(), &cltest.FixtureChainID, evmtypes.Nonce(42))) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, ethKeyStore.IncrementNextSequence(keyState.Address.Address(), &cltest.FixtureChainID, evmtypes.Nonce(0))) + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + eb.IncrementNextSequence(fromAddress, nonce) // Nonce bumped to 1 - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, keyState.Address.Address()) + nonce, err = eb.GetNextSequence(fromAddress) require.NoError(t, err) - require.Equal(t, int64(1), nonce) + require.Equal(t, int64(1), int64(nonce)) } func TestEthBroadcaster_Trigger(t *testing.T) { @@ -1733,7 +1732,7 @@ func TestEthBroadcaster_EthTxInsertEventCausesTriggerToFire(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) eventBroadcaster := cltest.NewEventBroadcaster(t, evmcfg.Database().URL()) require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) @@ -1761,8 +1760,8 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, kst, true) - _, disabledAddress := cltest.MustInsertRandomKeyReturningState(t, kst, false) + _, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst) + _, disabledAddress := cltest.RandomKey{Disabled: true}.MustInsertWithState(t, kst) ethNodeNonce := uint64(22) @@ -1780,6 +1779,10 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, nil, lggr, checkerFactory, false) err := eb.Start(testutils.Context(t)) assert.NoError(t, err) @@ -1789,68 +1792,208 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { testutils.WaitForLogMessage(t, observed, "Skipping sequence auto-sync") }) - t.Run("when eth node returns nonce, successfully sets nonce", func(t *testing.T) { + t.Run("when nonce syncer returns new nonce, successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(ethNodeNonce, nil).Once() - + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() require.NoError(t, eb.Start(ctx)) defer func() { assert.NoError(t, eb.Close()) }() - testutils.WaitForLogMessage(t, observed, "Fast-forwarded nonce") + testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") - // Check keyState to make sure it has correct nonce assigned - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + // Check nextSequenceMap to make sure it has correct nonce assigned + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(ethNodeNonce), nonce) + assert.Equal(t, strconv.FormatUint(ethNodeNonce, 10), nonce.String()) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) - require.NoError(t, err) - assert.Equal(t, int64(0), nonce) + _, err = eb.GetNextSequence(disabledAddress) + require.Error(t, err) }) ethNodeNonce++ observed.TakeAll() - t.Run("when eth node returns error, retries and successfully sets nonce", func(t *testing.T) { + t.Run("when nonce syncer returns error, retries and successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) + txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) + + kst := ksmocks.NewEth(t) + addresses := []gethCommon.Address{fromAddress} + kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) eb.XXXTestDisableUnstartedTxAutoProcessing() - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(uint64(0), errors.New("something exploded")).Once() - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(account gethCommon.Address) bool { - return account.Hex() == fromAddress.Hex() - })).Return(ethNodeNonce, nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil) require.NoError(t, eb.Start(ctx)) defer func() { assert.NoError(t, eb.Close()) }() - testutils.WaitForLogMessage(t, observed, "Fast-forwarded nonce") + testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") // Check keyState to make sure it has correct nonce assigned - var nonce int64 - err := db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, fromAddress) + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(ethNodeNonce), nonce) + assert.Equal(t, int64(ethNodeNonce), int64(nonce)) // The disabled key did not get updated - err = db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 ORDER BY created_at ASC, id ASC`, disabledAddress) + _, err = eb.GetNextSequence(disabledAddress) + require.Error(t, err) + }) + +} + +func Test_LoadSequenceMap(t *testing.T) { + t.Parallel() + t.Run("set next nonce using entries from tx table", func(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(0), fromAddress) + cltest.MustInsertUnconfirmedEthTx(t, txStore, int64(1), fromAddress) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(2), int64(nonce)) + }) + + t.Run("set next nonce using client when not found in tx table", func(t *testing.T) { + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(10), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(fromAddress) require.NoError(t, err) - assert.Equal(t, int64(0), nonce) + assert.Equal(t, int64(10), int64(nonce)) }) +} + +func Test_NextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + randNonce := testutils.NewRandomPositiveInt64() + _, addr1 := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.FixtureChainID)) + + nonce, err := eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce, int64(nonce)) + + randAddr1 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr1) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + + randAddr2 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr2) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr2.Hex())) + +} + +func Test_IncrementNextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + randNonce := testutils.NewRandomPositiveInt64() + _, addr1 := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + nonce, err := eb.GetNextSequence(addr1) + require.NoError(t, err) + eb.IncrementNextSequence(addr1, nonce) + + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+1, int64(nonce)) + + eb.IncrementNextSequence(addr1, nonce) + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+2, int64(nonce)) + + randAddr1 := utils.RandomAddress() + _, err = eb.GetNextSequence(randAddr1) + require.Error(t, err) + assert.Contains(t, err.Error(), fmt.Sprintf("address not found in next sequence map: %s", randAddr1.Hex())) + + // verify it didnt get changed by any erroring calls + nonce, err = eb.GetNextSequence(addr1) + require.NoError(t, err) + assert.Equal(t, randNonce+2, int64(nonce)) +} + +func Test_SetNextNonce(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() + + ethClient := evmtest.NewEthClientMockWithDefaultChain(t) + evmcfg := evmtest.NewChainScopedConfig(t, cfg) + checkerFactory := &txmgr.CheckerFactory{Client: ethClient} + _, fromAddress := cltest.MustInsertRandomKey(t, ks) + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() + eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) + + t.Run("update next nonce", func(t *testing.T) { + nonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(0), int64(nonce)) + eb.SetNextSequence(fromAddress, evmtypes.Nonce(24)) + + newNextNonce, err := eb.GetNextSequence(fromAddress) + require.NoError(t, err) + assert.Equal(t, int64(24), int64(newNextNonce)) + }) } type testCheckerFactory struct { diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 464cf6f9c59..39781e83f4c 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -47,7 +47,7 @@ func NewTxm( // create tx attempt builder txAttemptBuilder := NewEvmTxAttemptBuilder(*client.ConfiguredChainID(), fCfg, keyStore, estimator) txStore := NewTxStore(db, lggr, dbConfig) - txNonceSyncer := NewNonceSyncer(txStore, lggr, client, keyStore) + txNonceSyncer := NewNonceSyncer(txStore, lggr, client) txmCfg := NewEvmTxmConfig(chainConfig) // wrap Evm specific config feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config @@ -130,5 +130,5 @@ func NewEvmBroadcaster( checkerFactory TransmitCheckerFactory, autoSyncNonce bool, ) *Broadcaster { - return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, eventBroadcaster, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, stringToGethAddress) + return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, eventBroadcaster, txAttemptBuilder, nonceSyncer, logger, checkerFactory, autoSyncNonce, stringToGethAddress, evmtypes.GenerateNextNonce) } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index e0070e35b17..32246b06cea 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -117,8 +117,8 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() // Add some fromAddresses - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) + cltest.MustInsertRandomKey(t, ethKeyStore) estimator := gasmocks.NewEvmEstimator(t) lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() @@ -185,10 +185,9 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) nonce := int64(0) ctx := testutils.Context(t) @@ -599,15 +598,13 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -666,9 +663,8 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t * ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // tx is not forwarded and doesn't have meta set. EthConfirmer should handle nil meta values etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress) @@ -715,15 +711,13 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) var attempts []txmgr.TxAttempt @@ -773,13 +767,11 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ctx := testutils.Context(t) etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -801,18 +793,16 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t cfg := configtest.NewTestGeneralConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - chainId1, chainId2 := 1, 2 - _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId1) - _, fromAddress1_2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId1) - _, fromAddress2_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, chainId2) + _, fromAddress1_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, fromAddress1_2 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, fromAddress2_1 := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(20), nil) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -873,15 +863,13 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -961,7 +949,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" eth_tx is now confirmed, with the // two below it "confirmed_missing_receipt" and the "bottom" eth_tx also confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) @@ -1021,7 +1010,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1065,7 +1055,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it still "confirmed_missing_receipt" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1105,7 +1096,8 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) { // Expected state is that the "top" two eth_txes are now confirmed, with the // one below it marked as "fatal_error" and the bottom one remains confirmed - etx3, err := txStore.FindTxWithAttempts(etx3.ID) + var err error + etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) require.Equal(t, txmgrcommon.TxConfirmed, etx3.State) etx2, err = txStore.FindTxWithAttempts(etx2.ID) @@ -1131,15 +1123,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1182,6 +1172,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) { // Expected state is that the "top" eth_tx is untouched but the other two // are marked as unconfirmed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) @@ -1211,15 +1202,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1250,6 +1239,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t require.NoError(t, ec.CheckConfirmedMissingReceipt(ctx)) // Expected state is that all txes are marked as unconfirmed, since the batch call had failed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxUnconfirmed, etx0.State) @@ -1276,15 +1266,13 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) - + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) ctx := testutils.Context(t) // STATE @@ -1321,6 +1309,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa require.NoError(t, ec.CheckConfirmedMissingReceipt(ctx)) // Expected state is that all transactions since failed batch will be unconfirmed + var err error etx0, err = txStore.FindTxWithAttempts(etx0.ID) assert.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx0.State) @@ -1348,7 +1337,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmFromAddress := fromAddress currentHead := int64(30) gasBumpThreshold := int64(10) @@ -1360,13 +1349,12 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { mustInsertConfirmedEthTx(t, txStore, nonce, fromAddress) nonce++ - _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) evmOtherAddress := otherAddress lggr := logger.TestLogger(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) t.Run("returns nothing when there are no transactions", func(t *testing.T) { etxs, err := ec.FindTxsRequiringRebroadcast(testutils.Context(t), lggr, evmFromAddress, currentHead, gasBumpThreshold, 10, 0, &cltest.FixtureChainID) @@ -1747,8 +1735,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Use a mock keystore for this test - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) oldEnough := int64(19) nonce := int64(0) @@ -1773,7 +1760,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { mock.Anything).Return(nil, errors.New("signing error")).Once() // Do the thing - err = ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) + err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.Error(t, err) require.Contains(t, err.Error(), "signing error") @@ -1804,7 +1791,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1836,7 +1823,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1875,7 +1862,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1891,7 +1878,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing if there is an attempt without BroadcastBeforeBlockNum set", func(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1921,7 +1908,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1961,7 +1948,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -2012,7 +1999,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), fromAddress).Return(clienttypes.Unknown, errors.New("some network error")).Once() // Do the thing - err = ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) + err := ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead) require.Error(t, err) require.Contains(t, err.Error(), "some network error") @@ -2080,6 +2067,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Creates new attempt as normal if currentHead is not high enough require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) + var err error etx2, err = txStore.FindTxWithAttempts(etx2.ID) require.NoError(t, err) assert.Equal(t, txmgrcommon.TxConfirmedMissingReceipt, etx2.State) @@ -2120,7 +2108,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2157,7 +2145,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2196,7 +2184,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2217,8 +2205,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60500000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2226,7 +2213,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2248,8 +2235,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60480000000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 @@ -2257,7 +2243,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do the thing require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2265,7 +2251,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // No new tx attempts require.Len(t, etx3.TxAttempts, 4) - attempt3_4 := etx3.TxAttempts[0] + attempt3_4 = etx3.TxAttempts[0] assert.Equal(t, gasPrice.Int64(), attempt3_4.TxFee.Legacy.ToInt().Int64()) }) @@ -2294,7 +2280,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && gasTipCap.ToInt().Cmp(tx.GasTipCap()) == 0 }), fromAddress).Return(clienttypes.Successful, nil).Once() require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2317,8 +2303,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.GWei(1000) }) newCfg := evmtest.NewChainScopedConfig(t, gcfg) - ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) - require.NoError(t, err) + ec2 := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { @@ -2326,7 +2311,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { }), fromAddress).Return(clienttypes.Successful, nil).Once() require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2334,9 +2319,8 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // No new tx attempts require.Len(t, etx4.TxAttempts, 2) - attempt4_2 := etx4.TxAttempts[0] - assert.Equal(t, assets.GWei(999).Int64(), attempt4_2.TxFee.DynamicTipCap.ToInt().Int64()) - assert.Equal(t, assets.GWei(1000).Int64(), attempt4_2.TxFee.DynamicFeeCap.ToInt().Int64()) + assert.Equal(t, assets.GWei(999).Int64(), etx4.TxAttempts[0].TxFee.DynamicTipCap.ToInt().Int64()) + assert.Equal(t, assets.GWei(1000).Int64(), etx4.TxAttempts[0].TxFee.DynamicFeeCap.ToInt().Int64()) }) require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1, gas_tip_cap=$2, gas_fee_cap=$3 WHERE id=$4 RETURNING *`, @@ -2364,7 +2348,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Do it require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) - + var err error etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) @@ -2405,8 +2389,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("terminally underpriced transaction with in_progress attempt is retried with more gas", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) originalBroadcastAt := time.Unix(1616509100, 0) etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) @@ -2428,12 +2411,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) }) - realKst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in legacy mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2456,7 +2436,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh ).Run(func(args mock.Arguments) { unsignedLegacyTx := args.Get(1).(*types.Transaction) // Use the real keystore to do the actual signing - thisSignedLegacyTx, err := realKst.SignTx(fromAddress, unsignedLegacyTx, testutils.FixtureChainID) + thisSignedLegacyTx, err := ethKeyStore.SignTx(fromAddress, unsignedLegacyTx, testutils.FixtureChainID) require.NoError(t, err) *signedLegacyTx = *thisSignedLegacyTx }).Times(4) // 3 failures 1 success @@ -2465,8 +2445,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh t.Run("multiple gas bumps with existing broadcast attempts are retried with more gas until success in EIP-1559 mode", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, nonce, fromAddress) nonce++ @@ -2489,7 +2468,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh ).Run(func(args mock.Arguments) { unsignedDxFeeTx := args.Get(1).(*types.Transaction) // Use the real keystore to do the actual signing - thisSignedDxFeeTx, err := realKst.SignTx(fromAddress, unsignedDxFeeTx, testutils.FixtureChainID) + thisSignedDxFeeTx, err := ethKeyStore.SignTx(fromAddress, unsignedDxFeeTx, testutils.FixtureChainID) require.NoError(t, err) *signedDxFeeTx = *thisSignedDxFeeTx }).Times(4) // 3 failures 1 success @@ -2507,7 +2486,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, err := ethKeyStore.EnabledKeysForChain(testutils.FixtureChainID) require.NoError(t, err) @@ -2531,8 +2510,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { insufficientEthError := errors.New("insufficient funds for gas * price + value") t.Run("saves attempt with state 'insufficient_eth' if eth node returns this error", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2558,8 +2536,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("does not bump gas when previous error was 'out of eth', instead resubmits existing transaction", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2584,8 +2561,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { }) t.Run("saves the attempt as broadcast after node wallet has been topped up with sufficient balance", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) expectedBumpedGasPrice := big.NewInt(20000000000) require.Greater(t, expectedBumpedGasPrice.Int64(), attempt1_1.TxFee.Legacy.ToInt().Int64()) @@ -2617,8 +2593,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { c.EVM[0].GasEstimator.BumpTxDepth = ptr(uint32(depth)) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) for i := 0; i < etxCount; i++ { n := nonce @@ -2648,13 +2623,12 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) config := newTestChainScopedConfig(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -2822,7 +2796,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) config := newTestChainScopedConfig(t) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) @@ -2835,8 +2809,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts one eth_tx if it falls within in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2851,8 +2824,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("uses default gas limit if overrideGasLimit is 0", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && @@ -2867,8 +2839,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("rebroadcasts several eth_txes in nonce range", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(*etx1.Sequence) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && tx.Gas() == uint64(overrideGasLimit) @@ -2882,8 +2853,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("broadcasts zero transactions if eth_tx doesn't exist for that nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(1) @@ -2909,8 +2879,7 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { t.Run("zero transactions use default gas limit if override wasn't specified", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) - require.NoError(t, err) + ec := cltest.NewEthConfirmer(t, txStore, ethClient, config, ethKeyStore, nil) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.Nonce() == uint64(0) && tx.GasPrice().Int64() == gasPriceWei.Legacy.Int64() && uint32(tx.Gas()) == config.EVM().GasEstimator().LimitDefault() @@ -2929,7 +2898,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, config.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -2954,11 +2923,10 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) t.Run("doesn't process task runs that are not suspended (possibly already previously resumed)", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -2967,17 +2935,16 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { cltest.MustInsertEthReceipt(t, txStore, head.Number-minConfirmations, head.Hash, etx.TxAttempts[0].Hash) pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) - err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) + err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) }) t.Run("doesn't process task runs where the receipt is younger than minConfirmations", func(t *testing.T) { - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(uuid.UUID, interface{}, error) error { t.Fatal("No value expected") return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -2987,7 +2954,7 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2 WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) - err = ec.ResumePendingTaskRuns(testutils.Context(t), &head) + err := ec.ResumePendingTaskRuns(testutils.Context(t), &head) require.NoError(t, err) }) @@ -2995,12 +2962,11 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("processes eth_txes with receipts older than minConfirmations", func(t *testing.T) { ch := make(chan interface{}) var err error - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) @@ -3035,12 +3001,11 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { t.Run("processes eth_txes with receipt older than minConfirmations that reverted", func(t *testing.T) { ch := make(chan interface{}) var err error - ec, err := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { + ec := cltest.NewEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { err = thisErr ch <- value return nil }) - require.NoError(t, err) run := cltest.MustInsertPipelineRun(t, db) tr := cltest.MustInsertUnfinishedPipelineTaskRun(t, db, run.ID) diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go index 52cd50cba32..7b1ef8948c1 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -379,7 +379,15 @@ func (o *evmTxStore) preloadTxAttempts(txs []Tx) error { return nil } -func (o *evmTxStore) PreloadTxes(attempts []TxAttempt, qopts ...pg.QOpt) error { +func (o *evmTxStore) PreloadTxes(ctx context.Context, attempts []TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + return o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx)) +} + +// Only to be used for atomic transactions internal to the tx store +func (o *evmTxStore) preloadTxesAtomic(attempts []TxAttempt, qopts ...pg.QOpt) error { ethTxM := make(map[int64]Tx) for _, attempt := range attempts { ethTxM[attempt.TxID] = Tx{} @@ -454,7 +462,7 @@ func (o *evmTxStore) TxAttempts(offset, limit int) (txs []TxAttempt, count int, return } txs = dbEthTxAttemptsToEthTxAttempts(dbTxs) - err = o.PreloadTxes(txs) + err = o.preloadTxesAtomic(txs) return } @@ -469,7 +477,7 @@ func (o *evmTxStore) FindTxAttempt(hash common.Hash) (*TxAttempt, error) { var attempt TxAttempt dbTxAttempt.ToTxAttempt(&attempt) attempts := []TxAttempt{attempt} - err := o.PreloadTxes(attempts) + err := o.preloadTxesAtomic(attempts) return &attempts[0], err } @@ -543,7 +551,7 @@ func (o *evmTxStore) FindTxWithAttempts(etxID int64) (etx Tx, err error) { return pkgerrors.Wrapf(err, "failed to find eth_tx with id %d", etxID) } dbEtx.ToTx(&etx) - if err = o.LoadTxAttempts(&etx, pg.WithQueryer(tx)); err != nil { + if err = o.loadTxAttemptsAtomic(&etx, pg.WithQueryer(tx)); err != nil { return pkgerrors.Wrapf(err, "failed to load evm.tx_attempts for eth_tx with id %d", etxID) } if err = loadEthTxAttemptsReceipts(tx, &etx); err != nil { @@ -569,6 +577,7 @@ func (o *evmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]TxAttempt, er return txAttempts, pkgerrors.Wrap(err, "FindTxAttemptConfirmedByTxIDs failed") } +// Only used internally for atomic transactions func (o *evmTxStore) LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error { qq := o.q.WithOpts(qopts...) ethTxIDs := make([]int64, len(etxs)) @@ -591,7 +600,15 @@ func (o *evmTxStore) LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error { return nil } -func (o *evmTxStore) LoadTxAttempts(etx *Tx, qopts ...pg.QOpt) error { +func (o *evmTxStore) LoadTxAttempts(ctx context.Context, etx *Tx) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + return o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx)) +} + +// Only to be used for atomic transactions internal to the tx store +func (o *evmTxStore) loadTxAttemptsAtomic(etx *Tx, qopts ...pg.QOpt) error { return o.LoadTxesAttempts([]*Tx{etx}, qopts...) } @@ -646,7 +663,11 @@ func loadConfirmedAttemptsReceipts(q pg.Queryer, attempts []TxAttempt) error { // FindTxAttemptsRequiringResend returns the highest priced attempt for each // eth_tx that was last sent before or at the given time (up to limit) -func (o *evmTxStore) FindTxAttemptsRequiringResend(olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) (attempts []TxAttempt, err error) { +func (o *evmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) (attempts []TxAttempt, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var limit null.Uint32 if maxInFlightTransactions > 0 { limit = null.Uint32From(maxInFlightTransactions) @@ -654,7 +675,7 @@ func (o *evmTxStore) FindTxAttemptsRequiringResend(olderThan time.Time, maxInFli var dbAttempts []DbEthTxAttempt // this select distinct works because of unique index on evm.txes // (evm_chain_id, from_address, nonce) - err = o.q.Select(&dbAttempts, ` + err = qq.Select(&dbAttempts, ` SELECT DISTINCT ON (evm.txes.nonce) evm.tx_attempts.* FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state IN ('unconfirmed', 'confirmed_missing_receipt') @@ -667,7 +688,11 @@ LIMIT $4 return attempts, pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringResend failed to load evm.tx_attempts") } -func (o *evmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { +func (o *evmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) // Deliberately do nothing on NULL broadcast_at because that indicates the // tx has been moved into a state where broadcast_at is not relevant, e.g. // fatally errored. @@ -675,15 +700,19 @@ func (o *evmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { // Since EthConfirmer/EthResender can race (totally OK since highest // priced transaction always wins) we only want to update broadcast_at if // our version is later. - _, err := o.q.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) + _, err := qq.Exec(`UPDATE evm.txes SET broadcast_at = $1 WHERE id = ANY($2) AND broadcast_at < $1`, now, pq.Array(etxIDs)) return pkgerrors.Wrap(err, "updateBroadcastAts failed to update evm.txes") } // SetBroadcastBeforeBlockNum updates already broadcast attempts with the // current block number. This is safe no matter how old the head is because if // the attempt is already broadcast it _must_ have been before this head. -func (o *evmTxStore) SetBroadcastBeforeBlockNum(blockNum int64, chainID *big.Int) error { - _, err := o.q.Exec( +func (o *evmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID *big.Int) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + _, err := qq.Exec( `UPDATE evm.tx_attempts SET broadcast_before_block_num = $1 FROM evm.txes @@ -694,9 +723,13 @@ AND evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.evm_chain_id = $2`, return pkgerrors.Wrap(err, "SetBroadcastBeforeBlockNum failed") } -func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) (attempts []TxAttempt, err error) { +func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) (attempts []TxAttempt, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbAttempts []DbEthTxAttempt - err = o.q.Select(&dbAttempts, + err = qq.Select(&dbAttempts, `SELECT DISTINCT ON (evm.tx_attempts.eth_tx_id) evm.tx_attempts.* FROM evm.tx_attempts JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id AND evm.txes.state = 'confirmed_missing_receipt' @@ -710,8 +743,12 @@ func (o *evmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) (at return } -func (o *evmTxStore) UpdateTxsUnconfirmed(ids []int64) error { - _, err := o.q.Exec(`UPDATE evm.txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) +func (o *evmTxStore) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + _, err := qq.Exec(`UPDATE evm.txes SET state='unconfirmed' WHERE id = ANY($1)`, pq.Array(ids)) if err != nil { return pkgerrors.Wrap(err, "UpdateEthTxsUnconfirmed failed to execute") @@ -719,8 +756,12 @@ func (o *evmTxStore) UpdateTxsUnconfirmed(ids []int64) error { return nil } -func (o *evmTxStore) FindTxAttemptsRequiringReceiptFetch(chainID *big.Int) (attempts []TxAttempt, err error) { - err = o.q.Transaction(func(tx pg.Queryer) error { +func (o *evmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID *big.Int) (attempts []TxAttempt, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { var dbAttempts []DbEthTxAttempt err = tx.Select(&dbAttempts, ` SELECT evm.tx_attempts.* FROM evm.tx_attempts @@ -732,13 +773,17 @@ ORDER BY evm.txes.nonce ASC, evm.tx_attempts.gas_price DESC, evm.tx_attempts.gas return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - err = o.PreloadTxes(attempts, pg.WithQueryer(tx)) + err = o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) return pkgerrors.Wrap(err, "FindEthTxAttemptsRequiringReceiptFetch failed to load evm.txes") }, pg.OptReadOnlyTx()) return } -func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int) (err error) { +func (o *evmTxStore) SaveFetchedReceipts(ctx context.Context, r []*evmtypes.Receipt, chainID *big.Int) (err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) receipts := toOnchainReceipt(r) if len(receipts) == 0 { return nil @@ -815,7 +860,7 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int stmt = sqlx.Rebind(sqlx.DOLLAR, stmt) - err = o.q.ExecQ(stmt, valueArgs...) + err = qq.ExecQ(stmt, valueArgs...) return pkgerrors.Wrap(err, "SaveFetchedReceipts failed to save receipts") } @@ -839,8 +884,12 @@ func (o *evmTxStore) SaveFetchedReceipts(r []*evmtypes.Receipt, chainID *big.Int // // We will continue to try to fetch a receipt for these attempts until all // attempts are below the finality depth from current head. -func (o *evmTxStore) MarkAllConfirmedMissingReceipt(chainID *big.Int) (err error) { - res, err := o.q.Exec(` +func (o *evmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) (err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + res, err := qq.Exec(` UPDATE evm.txes SET state = 'confirmed_missing_receipt' FROM ( @@ -868,6 +917,9 @@ WHERE state = 'unconfirmed' } func (o *evmTxStore) GetInProgressTxAttempts(ctx context.Context, address common.Address, chainID *big.Int) (attempts []TxAttempt, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Transaction(func(tx pg.Queryer) error { var dbAttempts []DbEthTxAttempt @@ -880,7 +932,7 @@ WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND e return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.tx_attempts") } attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) - err = o.PreloadTxes(attempts, pg.WithQueryer(tx)) + err = o.preloadTxesAtomic(attempts, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) return pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed to load evm.txes") }, pg.OptReadOnlyTx()) return attempts, pkgerrors.Wrap(err, "getInProgressEthTxAttempts failed") @@ -889,6 +941,9 @@ WHERE evm.tx_attempts.state = 'in_progress' AND evm.txes.from_address = $1 AND e func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockNum int64, chainID *big.Int) (receiptsPlus []ReceiptPlus, err error) { var rs []dbReceiptPlus + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() err = o.q.SelectContext(ctx, &rs, ` SELECT pipeline_task_runs.id, evm.receipts.receipt, COALESCE((evm.txes.meta->>'FailOnRevert')::boolean, false) "FailOnRevert" FROM pipeline_task_runs INNER JOIN pipeline_runs ON pipeline_runs.id = pipeline_task_runs.pipeline_run_id @@ -902,10 +957,24 @@ func (o *evmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, blockN return } +func (o *evmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (nonce evmtypes.Nonce, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + sql := `SELECT nonce FROM evm.txes WHERE from_address = $1 AND evm_chain_id = $2 AND nonce IS NOT NULL ORDER BY nonce DESC LIMIT 1` + err = qq.Get(&nonce, sql, fromAddress, chainId.String()) + return +} + // FindTxWithIdempotencyKey returns any broadcast ethtx with the given idempotencyKey and chainID -func (o *evmTxStore) FindTxWithIdempotencyKey(idempotencyKey string, chainID *big.Int) (etx *Tx, err error) { +func (o *evmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID *big.Int) (etx *Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx - err = o.q.Get(&dbEtx, `SELECT * FROM evm.txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) + err = qq.Get(&dbEtx, `SELECT * FROM evm.txes WHERE idempotency_key = $1 and evm_chain_id = $2`, idempotencyKey, chainID.String()) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil @@ -918,9 +987,13 @@ func (o *evmTxStore) FindTxWithIdempotencyKey(idempotencyKey string, chainID *bi } // FindTxWithSequence returns any broadcast ethtx with the given nonce -func (o *evmTxStore) FindTxWithSequence(fromAddress common.Address, nonce evmtypes.Nonce) (etx *Tx, err error) { +func (o *evmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common.Address, nonce evmtypes.Nonce) (etx *Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) etx = new(Tx) - err = o.q.Transaction(func(tx pg.Queryer) error { + err = qq.Transaction(func(tx pg.Queryer) error { var dbEtx DbEthTx err = tx.Get(&dbEtx, ` SELECT * FROM evm.txes WHERE from_address = $1 AND nonce = $2 AND state IN ('confirmed', 'confirmed_missing_receipt', 'unconfirmed') @@ -929,7 +1002,7 @@ SELECT * FROM evm.txes WHERE from_address = $1 AND nonce = $2 AND state IN ('con return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.txes") } dbEtx.ToTx(etx) - err = o.LoadTxAttempts(etx, pg.WithQueryer(tx)) + err = o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) return pkgerrors.Wrap(err, "FindEthTxWithNonce failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) if errors.Is(err, sql.ErrNoRows) { @@ -964,8 +1037,12 @@ AND evm.tx_attempts.eth_tx_id = $1 return pkgerrors.Wrap(err, "deleteEthReceipts failed") } -func (o *evmTxStore) UpdateTxForRebroadcast(etx Tx, etxAttempt TxAttempt) error { - return o.q.Transaction(func(tx pg.Queryer) error { +func (o *evmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx Tx, etxAttempt TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + return qq.Transaction(func(tx pg.Queryer) error { if err := deleteEthReceipts(tx, etx.ID); err != nil { return pkgerrors.Wrapf(err, "deleteEthReceipts failed for etx %v", etx.ID) } @@ -976,8 +1053,12 @@ func (o *evmTxStore) UpdateTxForRebroadcast(etx Tx, etxAttempt TxAttempt) error }) } -func (o *evmTxStore) FindTransactionsConfirmedInBlockRange(highBlockNumber, lowBlockNumber int64, chainID *big.Int) (etxs []*Tx, err error) { - err = o.q.Transaction(func(tx pg.Queryer) error { +func (o *evmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber, lowBlockNumber int64, chainID *big.Int) (etxs []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + err = qq.Transaction(func(tx pg.Queryer) error { var dbEtxs []DbEthTx err = tx.Select(&dbEtxs, ` SELECT DISTINCT evm.txes.* FROM evm.txes @@ -991,7 +1072,7 @@ ORDER BY nonce ASC } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - if err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)); err != nil { + if err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)); err != nil { return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.tx_attempts") } err = loadEthTxesAttemptsReceipts(tx, etxs) @@ -1017,12 +1098,16 @@ func saveAttemptWithNewState(q pg.Queryer, timeout time.Duration, logger logger. }) } -func (o *evmTxStore) SaveInsufficientFundsAttempt(timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { +func (o *evmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if !(attempt.State == txmgrtypes.TxAttemptInProgress || attempt.State == txmgrtypes.TxAttemptInsufficientFunds) { return errors.New("expected state to be either in_progress or insufficient_eth") } attempt.State = txmgrtypes.TxAttemptInsufficientFunds - return pkgerrors.Wrap(saveAttemptWithNewState(o.q, timeout, o.logger, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") + return pkgerrors.Wrap(saveAttemptWithNewState(qq, timeout, o.logger, *attempt, broadcastAt), "saveInsufficientEthAttempt failed") } func saveSentAttempt(q pg.Queryer, timeout time.Duration, logger logger.Logger, attempt *TxAttempt, broadcastAt time.Time) error { @@ -1033,11 +1118,18 @@ func saveSentAttempt(q pg.Queryer, timeout time.Duration, logger logger.Logger, return pkgerrors.Wrap(saveAttemptWithNewState(q, timeout, logger, *attempt, broadcastAt), "saveSentAttempt failed") } -func (o *evmTxStore) SaveSentAttempt(timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { - return saveSentAttempt(o.q, timeout, o.logger, attempt, broadcastAt) +func (o *evmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + return saveSentAttempt(qq, timeout, o.logger, attempt, broadcastAt) } func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt, broadcastAt time.Time) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err := qq.Transaction(func(tx pg.Queryer) error { if err := saveSentAttempt(tx, timeout, o.logger, attempt, broadcastAt); err != nil { @@ -1053,8 +1145,10 @@ func (o *evmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, tim } func (o *evmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("DeleteInProgressAttempt: expected attempt state to be in_progress") } @@ -1066,7 +1160,11 @@ func (o *evmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt TxAtte } // SaveInProgressAttempt inserts or updates an attempt -func (o *evmTxStore) SaveInProgressAttempt(attempt *TxAttempt) error { +func (o *evmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if attempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("SaveInProgressAttempt failed: attempt state must be in_progress") } @@ -1074,16 +1172,16 @@ func (o *evmTxStore) SaveInProgressAttempt(attempt *TxAttempt) error { dbAttempt.FromTxAttempt(attempt) // Insert is the usual mode because the attempt is new if attempt.ID == 0 { - query, args, e := o.q.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) + query, args, e := qq.BindNamed(insertIntoEthTxAttemptsQuery, &dbAttempt) if e != nil { return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to BindNamed") } - e = o.q.Get(&dbAttempt, query, args...) + e = qq.Get(&dbAttempt, query, args...) dbAttempt.ToTxAttempt(attempt) return pkgerrors.Wrap(e, "SaveInProgressAttempt failed to insert into evm.tx_attempts") } // Update only applies to case of insufficient eth and simply changes the state to in_progress - res, err := o.q.Exec(`UPDATE evm.tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) + res, err := qq.Exec(`UPDATE evm.tx_attempts SET state=$1, broadcast_before_block_num=$2 WHERE id=$3`, dbAttempt.State, dbAttempt.BroadcastBeforeBlockNum, dbAttempt.ID) if err != nil { return pkgerrors.Wrap(err, "SaveInProgressAttempt failed to update evm.tx_attempts") } @@ -1106,6 +1204,9 @@ func (o *evmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common if gasBumpThreshold == 0 { return } + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Transaction(func(tx pg.Queryer) error { stmt := ` @@ -1121,7 +1222,7 @@ ORDER BY nonce ASC } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)) + err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) return pkgerrors.Wrap(err, "FindEthTxsRequiringGasBump failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) return @@ -1130,8 +1231,11 @@ ORDER BY nonce ASC // FindTxsRequiringResubmissionDueToInsufficientFunds returns transactions // that need to be re-sent because they hit an out-of-eth error on a previous // block -func (o *evmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (etxs []*Tx, err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address common.Address, chainID *big.Int) (etxs []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Transaction(func(tx pg.Queryer) error { var dbEtxs []DbEthTx err = tx.Select(&dbEtxs, ` @@ -1145,7 +1249,7 @@ ORDER BY nonce ASC } etxs = make([]*Tx, len(dbEtxs)) dbEthTxsToEvmEthTxPtrs(dbEtxs, etxs) - err = o.LoadTxesAttempts(etxs, pg.WithQueryer(tx)) + err = o.LoadTxesAttempts(etxs, pg.WithParentCtx(ctx), pg.WithQueryer(tx)) return pkgerrors.Wrap(err, "FindEthTxsRequiringResubmissionDueToInsufficientEth failed to load evm.tx_attempts") }, pg.OptReadOnlyTx()) return @@ -1158,8 +1262,11 @@ ORDER BY nonce ASC // // The job run will also be marked as errored in this case since we never got a // receipt and thus cannot pass on any transaction hash -func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(blockNum int64, finalityDepth uint32, chainID *big.Int, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) // cutoffBlockNum is a block height // Any 'confirmed_missing_receipt' eth_tx with all attempts older than this block height will be marked as errored // We will not try to query for receipts for this transaction any more @@ -1249,8 +1356,11 @@ GROUP BY e.id }) } -func (o *evmTxStore) SaveReplacementInProgressAttempt(oldAttempt TxAttempt, replacementAttempt *TxAttempt, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt TxAttempt, replacementAttempt *TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if oldAttempt.State != txmgrtypes.TxAttemptInProgress || replacementAttempt.State != txmgrtypes.TxAttemptInProgress { return errors.New("expected attempts to be in_progress") } @@ -1274,17 +1384,22 @@ func (o *evmTxStore) SaveReplacementInProgressAttempt(oldAttempt TxAttempt, repl } // Finds earliest saved transaction that has yet to be broadcast from the given address -func (o *evmTxStore) FindNextUnstartedTransactionFromAddress(etx *Tx, fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *Tx, fromAddress common.Address, chainID *big.Int) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx err := qq.Get(&dbEtx, `SELECT * FROM evm.txes WHERE from_address = $1 AND state = 'unstarted' AND evm_chain_id = $2 ORDER BY value ASC, created_at ASC, id ASC`, fromAddress, chainID.String()) dbEtx.ToTx(etx) return pkgerrors.Wrap(err, "failed to FindNextUnstartedTransactionFromAddress") } -func (o *evmTxStore) UpdateTxFatalError(etx *Tx, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) - +func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.State != txmgr.TxInProgress { return pkgerrors.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) } @@ -1308,11 +1423,12 @@ func (o *evmTxStore) UpdateTxFatalError(etx *Tx, qopts ...pg.QOpt) error { } // Updates eth attempt from in_progress to broadcast. Also updates the eth tx to unconfirmed. -// Before it updates both tables though it increments the next nonce from the keystore // One of the more complicated signatures. We have to accept variable pg.QOpt and QueryerFunc arguments -func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAttempt, NewAttemptState txmgrtypes.TxAttemptState, incrNextNonceCallback txmgrtypes.QueryerFunc, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) - +func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *Tx, attempt TxAttempt, NewAttemptState txmgrtypes.TxAttemptState) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.BroadcastAt == nil { return errors.New("unconfirmed transaction must have broadcast_at time") } @@ -1331,9 +1447,6 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAtt etx.State = txmgr.TxUnconfirmed attempt.State = NewAttemptState return qq.Transaction(func(tx pg.Queryer) error { - if err := incrNextNonceCallback(tx); err != nil { - return pkgerrors.Wrap(err, "SaveEthTxAttempt failed on incrNextNonceCallback") - } var dbEtx DbEthTx dbEtx.FromTx(etx) if err := tx.Get(&dbEtx, `UPDATE evm.txes SET state=$1, error=$2, broadcast_at=$3, initial_broadcast_at=$4 WHERE id = $5 RETURNING *`, dbEtx.State, dbEtx.Error, dbEtx.BroadcastAt, dbEtx.InitialBroadcastAt, dbEtx.ID); err != nil { @@ -1350,8 +1463,11 @@ func (o *evmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *Tx, attempt TxAtt } // Updates eth tx from unstarted to in_progress and inserts in_progress eth attempt -func (o *evmTxStore) UpdateTxUnstartedToInProgress(etx *Tx, attempt *TxAttempt, qopts ...pg.QOpt) error { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx, attempt *TxAttempt) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if etx.Sequence == nil { return errors.New("in_progress transaction must have nonce") } @@ -1411,8 +1527,11 @@ func (o *evmTxStore) UpdateTxUnstartedToInProgress(etx *Tx, attempt *TxAttempt, // an unfinished state because something went screwy the last time. Most likely // the node crashed in the middle of the ProcessUnstartedEthTxs loop. // It may or may not have been broadcast to an eth node. -func (o *evmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOpt) (etx *Tx, err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Address) (etx *Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) etx = new(Tx) if err != nil { return etx, pkgerrors.Wrap(err, "getInProgressEthTx failed") @@ -1427,7 +1546,7 @@ func (o *evmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOp return pkgerrors.Wrap(err, "GetTxInProgress failed while loading eth tx") } dbEtx.ToTx(etx) - if err = o.LoadTxAttempts(etx, pg.WithQueryer(tx)); err != nil { + if err = o.loadTxAttemptsAtomic(etx, pg.WithParentCtx(ctx), pg.WithQueryer(tx)); err != nil { return pkgerrors.Wrap(err, "GetTxInProgress failed while loading EthTxAttempts") } if len(etx.TxAttempts) != 1 || etx.TxAttempts[0].State != txmgrtypes.TxAttemptInProgress { @@ -1440,8 +1559,11 @@ func (o *evmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOp return etx, pkgerrors.Wrap(err, "getInProgressEthTx failed") } -func (o *evmTxStore) HasInProgressTransaction(account common.Address, chainID *big.Int, qopts ...pg.QOpt) (exists bool, err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) HasInProgressTransaction(ctx context.Context, account common.Address, chainID *big.Int) (exists bool, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Get(&exists, `SELECT EXISTS(SELECT 1 FROM evm.txes WHERE state = 'in_progress' AND from_address = $1 AND evm_chain_id = $2)`, account, chainID.String()) return exists, pkgerrors.Wrap(err, "hasInProgressTransaction failed") } @@ -1466,25 +1588,31 @@ func (o *evmTxStore) UpdateKeyNextSequence(newNextNonce, currentNextNonce evmtyp }) } -func (o *evmTxStore) countTransactionsWithState(fromAddress common.Address, state txmgrtypes.TxState, chainID *big.Int, qopts ...pg.QOpt) (count uint32, err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) countTransactionsWithState(ctx context.Context, fromAddress common.Address, state txmgrtypes.TxState, chainID *big.Int) (count uint32, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = $2 AND evm_chain_id = $3`, fromAddress, state, chainID.String()) return count, pkgerrors.Wrap(err, "failed to countTransactionsWithState") } // CountUnconfirmedTransactions returns the number of unconfirmed transactions -func (o *evmTxStore) CountUnconfirmedTransactions(fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) (count uint32, err error) { - return o.countTransactionsWithState(fromAddress, txmgr.TxUnconfirmed, chainID, qopts...) +func (o *evmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (count uint32, err error) { + return o.countTransactionsWithState(ctx, fromAddress, txmgr.TxUnconfirmed, chainID) } // CountUnstartedTransactions returns the number of unconfirmed transactions -func (o *evmTxStore) CountUnstartedTransactions(fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) (count uint32, err error) { - return o.countTransactionsWithState(fromAddress, txmgr.TxUnstarted, chainID, qopts...) +func (o *evmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (count uint32, err error) { + return o.countTransactionsWithState(ctx, fromAddress, txmgr.TxUnstarted, chainID) } -func (o *evmTxStore) CheckTxQueueCapacity(fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int, qopts ...pg.QOpt) (err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) CheckTxQueueCapacity(ctx context.Context, fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int) (err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) if maxQueuedTransactions == 0 { return nil } @@ -1501,9 +1629,12 @@ func (o *evmTxStore) CheckTxQueueCapacity(fromAddress common.Address, maxQueuedT return } -func (o *evmTxStore) CreateTransaction(txRequest TxRequest, chainID *big.Int, qopts ...pg.QOpt) (tx Tx, err error) { +func (o *evmTxStore) CreateTransaction(ctx context.Context, txRequest TxRequest, chainID *big.Int) (tx Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) var dbEtx DbEthTx - qq := o.q.WithOpts(qopts...) err = qq.Transaction(func(tx pg.Queryer) error { if txRequest.PipelineTaskRunID != nil { @@ -1528,7 +1659,7 @@ RETURNING "txes".* return pkgerrors.Wrap(err, "CreateEthTransaction failed to insert evm tx") } var pruned int64 - pruned, err = txRequest.Strategy.PruneQueue(o, pg.WithQueryer(tx)) + pruned, err = txRequest.Strategy.PruneQueue(ctx, o) if err != nil { return pkgerrors.Wrap(err, "CreateEthTransaction failed to prune evm.txes") } @@ -1542,8 +1673,11 @@ RETURNING "txes".* return etx, err } -func (o *evmTxStore) PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qopts ...pg.QOpt) (n int64, err error) { - qq := o.q.WithOpts(qopts...) +func (o *evmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (n int64, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) err = qq.Transaction(func(tx pg.Queryer) error { res, err := qq.Exec(` DELETE FROM evm.txes @@ -1566,12 +1700,16 @@ id < ( return } -func (o *evmTxStore) ReapTxHistory(minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { +func (o *evmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) // Delete old confirmed evm.txes // NOTE that this relies on foreign key triggers automatically removing // the evm.tx_attempts and evm.receipts linked to every eth_tx err := pg.Batch(func(_, limit uint) (count uint, err error) { - res, err := o.q.Exec(` + res, err := qq.Exec(` WITH old_enough_receipts AS ( SELECT tx_hash FROM evm.receipts WHERE block_number < $1 @@ -1599,7 +1737,7 @@ AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.Stri } // Delete old 'fatal_error' evm.txes err = pg.Batch(func(_, limit uint) (count uint, err error) { - res, err := o.q.Exec(` + res, err := qq.Exec(` DELETE FROM evm.txes WHERE created_at < $1 AND state = 'fatal_error' @@ -1620,7 +1758,25 @@ AND evm_chain_id = $2`, timeThreshold, chainID.String()) return nil } -func (o *evmTxStore) Abandon(chainID *big.Int, addr common.Address) error { - _, err := o.q.Exec(`UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) +func (o *evmTxStore) Abandon(ctx context.Context, chainID *big.Int, addr common.Address) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + _, err := qq.Exec(`UPDATE evm.txes SET state='fatal_error', nonce = NULL, error = 'abandoned' WHERE state IN ('unconfirmed', 'in_progress', 'unstarted') AND evm_chain_id = $1 AND from_address = $2`, chainID.String(), addr) return err } + +// Returns a context that contains the values of the provided context, +// and which is canceled when either the provided contextg or TxStore parent context is canceled. +func (o *evmTxStore) mergeContexts(ctx context.Context) (context.Context, context.CancelFunc) { + var cancel context.CancelCauseFunc + ctx, cancel = context.WithCancelCause(ctx) + stop := context.AfterFunc(o.q.ParentCtx, func() { + cancel(context.Cause(o.q.ParentCtx)) + }) + return ctx, func() { + stop() + cancel(context.Canceled) + } +} diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 913652b7c8b..e5b47c457b4 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -1,7 +1,6 @@ package txmgr_test import ( - "context" "database/sql" "fmt" "math/big" @@ -38,7 +37,7 @@ func TestORM_TransactionsWithAttempts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) // tx2 @@ -83,7 +82,7 @@ func TestORM_Transactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) // tx2 @@ -121,14 +120,12 @@ func TestORM(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) orm := cltest.NewTestTxStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - var err error var etx txmgr.Tx t.Run("InsertTx", func(t *testing.T) { etx = cltest.NewEthTx(t, fromAddress) - err = orm.InsertTx(&etx) - require.NoError(t, err) + require.NoError(t, orm.InsertTx(&etx)) assert.Greater(t, int(etx.ID), 0) cltest.AssertCount(t, db, "evm.txes", 1) }) @@ -136,16 +133,14 @@ func TestORM(t *testing.T) { var attemptD txmgr.TxAttempt t.Run("InsertTxAttempt", func(t *testing.T) { attemptD = cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) - err = orm.InsertTxAttempt(&attemptD) - require.NoError(t, err) + require.NoError(t, orm.InsertTxAttempt(&attemptD)) assert.Greater(t, int(attemptD.ID), 0) cltest.AssertCount(t, db, "evm.tx_attempts", 1) attemptL = cltest.NewLegacyEthTxAttempt(t, etx.ID) attemptL.State = txmgrtypes.TxAttemptBroadcast attemptL.TxFee = gas.EvmFee{Legacy: assets.NewWeiI(42)} - err = orm.InsertTxAttempt(&attemptL) - require.NoError(t, err) + require.NoError(t, orm.InsertTxAttempt(&attemptL)) assert.Greater(t, int(attemptL.ID), 0) cltest.AssertCount(t, db, "evm.tx_attempts", 2) }) @@ -159,6 +154,7 @@ func TestORM(t *testing.T) { cltest.AssertCount(t, db, "evm.receipts", 1) }) t.Run("FindTxWithAttempts", func(t *testing.T) { + var err error etx, err = orm.FindTxWithAttempts(etx.ID) require.NoError(t, err) require.Len(t, etx.TxAttempts, 2) @@ -192,7 +188,7 @@ func TestORM_FindTxAttemptConfirmedByTxIDs(t *testing.T) { orm := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) tx1 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, orm, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, orm, 1, 2, from) // tx2 @@ -248,7 +244,7 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { t.Run("returns nothing if there are no transactions", func(t *testing.T) { olderThan := time.Now() - attempts, err := txStore.FindTxAttemptsRequiringResend(olderThan, 10, &cltest.FixtureChainID, fromAddress) + attempts, err := txStore.FindTxAttemptsRequiringResend(testutils.Context(t), olderThan, 10, &cltest.FixtureChainID, fromAddress) require.NoError(t, err) assert.Len(t, attempts, 0) }) @@ -291,14 +287,14 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { t.Run("returns nothing if there are transactions from a different key", func(t *testing.T) { olderThan := time.Now() - attempts, err := txStore.FindTxAttemptsRequiringResend(olderThan, 10, &cltest.FixtureChainID, utils.RandomAddress()) + attempts, err := txStore.FindTxAttemptsRequiringResend(testutils.Context(t), olderThan, 10, &cltest.FixtureChainID, utils.RandomAddress()) require.NoError(t, err) assert.Len(t, attempts, 0) }) t.Run("returns the highest price attempt for each transaction that was last broadcast before or on the given time", func(t *testing.T) { olderThan := time.Unix(1616509200, 0) - attempts, err := txStore.FindTxAttemptsRequiringResend(olderThan, 0, &cltest.FixtureChainID, fromAddress) + attempts, err := txStore.FindTxAttemptsRequiringResend(testutils.Context(t), olderThan, 0, &cltest.FixtureChainID, fromAddress) require.NoError(t, err) assert.Len(t, attempts, 2) assert.Equal(t, attempt1_2.ID, attempts[0].ID) @@ -307,7 +303,7 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { t.Run("returns the highest price attempt for EIP-1559 transactions", func(t *testing.T) { olderThan := time.Unix(1616509400, 0) - attempts, err := txStore.FindTxAttemptsRequiringResend(olderThan, 0, &cltest.FixtureChainID, fromAddress) + attempts, err := txStore.FindTxAttemptsRequiringResend(testutils.Context(t), olderThan, 0, &cltest.FixtureChainID, fromAddress) require.NoError(t, err) assert.Len(t, attempts, 4) assert.Equal(t, attempt4_4.ID, attempts[3].ID) @@ -315,7 +311,7 @@ func TestORM_FindTxAttemptsRequiringResend(t *testing.T) { t.Run("applies limit", func(t *testing.T) { olderThan := time.Unix(1616509200, 0) - attempts, err := txStore.FindTxAttemptsRequiringResend(olderThan, 1, &cltest.FixtureChainID, fromAddress) + attempts, err := txStore.FindTxAttemptsRequiringResend(testutils.Context(t), olderThan, 1, &cltest.FixtureChainID, fromAddress) require.NoError(t, err) assert.Len(t, attempts, 1) assert.Equal(t, attempt1_2.ID, attempts[0].ID) @@ -329,7 +325,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) orm := cltest.NewTestTxStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) t.Run("does not update when broadcast_at is NULL", func(t *testing.T) { t.Parallel() @@ -340,7 +336,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { assert.Equal(t, nullTime, etx.BroadcastAt) currTime := time.Now() - err := orm.UpdateBroadcastAts(currTime, []int64{etx.ID}) + err := orm.UpdateBroadcastAts(testutils.Context(t), currTime, []int64{etx.ID}) require.NoError(t, err) etx, err = orm.FindTxWithAttempts(etx.ID) @@ -361,7 +357,7 @@ func TestORM_UpdateBroadcastAts(t *testing.T) { require.NoError(t, err) time2 := time.Date(2077, 8, 14, 10, 0, 0, 0, time.UTC) - err = orm.UpdateBroadcastAts(time2, []int64{etx.ID}) + err = orm.UpdateBroadcastAts(testutils.Context(t), time2, []int64{etx.ID}) require.NoError(t, err) etx, err = orm.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -378,7 +374,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) chainID := ethClient.ConfiguredChainID() @@ -387,7 +383,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { t.Run("saves block num to unconfirmed evm.tx_attempts without one", func(t *testing.T) { // Do the thing - require.NoError(t, txStore.SetBroadcastBeforeBlockNum(headNum, chainID)) + require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -404,7 +400,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { require.NoError(t, txStore.InsertTxAttempt(&attempt)) // Do the thing - require.NoError(t, txStore.SetBroadcastBeforeBlockNum(headNum, chainID)) + require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -420,7 +416,7 @@ func TestORM_SetBroadcastBeforeBlockNum(t *testing.T) { etxThisChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress, cfg.EVM().ChainID()) etxOtherChain := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress, testutils.SimulatedChainID) - require.NoError(t, txStore.SetBroadcastBeforeBlockNum(headNum, chainID)) + require.NoError(t, txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), headNum, chainID)) etxThisChain, err = txStore.FindTxWithAttempts(etxThisChain.ID) require.NoError(t, err) @@ -446,13 +442,13 @@ func TestORM_FindTxAttemptsConfirmedMissingReceipt(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) - attempts, err := txStore.FindTxAttemptsConfirmedMissingReceipt(ethClient.ConfiguredChainID()) + attempts, err := txStore.FindTxAttemptsConfirmedMissingReceipt(testutils.Context(t), ethClient.ConfiguredChainID()) require.NoError(t, err) @@ -468,13 +464,13 @@ func TestORM_UpdateTxsUnconfirmed(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) assert.Equal(t, etx0.State, txmgrcommon.TxConfirmedMissingReceipt) - require.NoError(t, txStore.UpdateTxsUnconfirmed([]int64{etx0.ID})) + require.NoError(t, txStore.UpdateTxsUnconfirmed(testutils.Context(t), []int64{etx0.ID})) etx0, err := txStore.FindTxWithAttempts(etx0.ID) require.NoError(t, err) @@ -489,13 +485,13 @@ func TestORM_FindTxAttemptsRequiringReceiptFetch(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( t, txStore, 0, 1, originalBroadcastAt, fromAddress) - attempts, err := txStore.FindTxAttemptsRequiringReceiptFetch(ethClient.ConfiguredChainID()) + attempts, err := txStore.FindTxAttemptsRequiringReceiptFetch(testutils.Context(t), ethClient.ConfiguredChainID()) require.NoError(t, err) assert.Len(t, attempts, 1) assert.Len(t, etx0.TxAttempts, 1) @@ -510,7 +506,7 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) originalBroadcastAt := time.Unix(1616509100, 0) etx0 := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt( @@ -525,7 +521,7 @@ func TestORM_SaveFetchedReceipts(t *testing.T) { TransactionIndex: uint(1), } - err := txStore.SaveFetchedReceipts([]*evmtypes.Receipt{&txmReceipt}, ethClient.ConfiguredChainID()) + err := txStore.SaveFetchedReceipts(testutils.Context(t), []*evmtypes.Receipt{&txmReceipt}, ethClient.ConfiguredChainID()) require.NoError(t, err) etx0, err = txStore.FindTxWithAttempts(etx0.ID) @@ -543,7 +539,7 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // create transaction 0 (nonce 0) that is unconfirmed (block 7) @@ -559,7 +555,7 @@ func TestORM_MarkAllConfirmedMissingReceipt(t *testing.T) { assert.Equal(t, etx1.State, txmgrcommon.TxConfirmed) // mark transaction 0 confirmed_missing_receipt - err := txStore.MarkAllConfirmedMissingReceipt(ethClient.ConfiguredChainID()) + err := txStore.MarkAllConfirmedMissingReceipt(testutils.Context(t), ethClient.ConfiguredChainID()) require.NoError(t, err) etx0, err = txStore.FindTxWithAttempts(etx0.ID) require.NoError(t, err) @@ -573,7 +569,7 @@ func TestORM_PreloadTxes(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("loads eth transaction", func(t *testing.T) { // insert etx with attempt @@ -587,7 +583,7 @@ func TestORM_PreloadTxes(t *testing.T) { attempts := []txmgr.TxAttempt{unloadedAttempt} - err := txStore.PreloadTxes(attempts) + err := txStore.PreloadTxes(testutils.Context(t), attempts) require.NoError(t, err) assert.Equal(t, etx.ID, attempts[0].Tx.ID) @@ -595,7 +591,7 @@ func TestORM_PreloadTxes(t *testing.T) { t.Run("returns nil when attempts slice is empty", func(t *testing.T) { emptyAttempts := []txmgr.TxAttempt{} - err := txStore.PreloadTxes(emptyAttempts) + err := txStore.PreloadTxes(testutils.Context(t), emptyAttempts) require.NoError(t, err) }) } @@ -608,13 +604,13 @@ func TestORM_GetInProgressTxAttempts(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // insert etx with attempt etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, int64(7), fromAddress, txmgrtypes.TxAttemptInProgress) // fetch attempt - attempts, err := txStore.GetInProgressTxAttempts(context.Background(), fromAddress, ethClient.ConfiguredChainID()) + attempts, err := txStore.GetInProgressTxAttempts(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) assert.Len(t, attempts, 1) @@ -629,7 +625,7 @@ func TestORM_FindReceiptsPendingConfirmation(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`) @@ -672,11 +668,11 @@ func Test_FindTxWithIdempotencyKey(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { idempotencyKey := "777" - etx, err := txStore.FindTxWithIdempotencyKey(idempotencyKey, big.NewInt(0)) + etx, err := txStore.FindTxWithIdempotencyKey(testutils.Context(t), idempotencyKey, big.NewInt(0)) require.NoError(t, err) assert.Nil(t, etx) }) @@ -688,7 +684,7 @@ func Test_FindTxWithIdempotencyKey(t *testing.T) { cltest.EvmTxRequestWithIdempotencyKey(idempotencyKey)) require.Equal(t, idempotencyKey, *etx.IdempotencyKey) - res, err := txStore.FindTxWithIdempotencyKey(idempotencyKey, big.NewInt(0)) + res, err := txStore.FindTxWithIdempotencyKey(testutils.Context(t), idempotencyKey, big.NewInt(0)) require.NoError(t, err) assert.Equal(t, etx.Sequence, res.Sequence) require.Equal(t, idempotencyKey, *res.IdempotencyKey) @@ -702,10 +698,10 @@ func TestORM_FindTxWithSequence(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("returns nil if no results", func(t *testing.T) { - etx, err := txStore.FindTxWithSequence(fromAddress, evmtypes.Nonce(777)) + etx, err := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, evmtypes.Nonce(777)) require.NoError(t, err) assert.Nil(t, etx) }) @@ -714,7 +710,7 @@ func TestORM_FindTxWithSequence(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 777, 1, fromAddress) require.Equal(t, evmtypes.Nonce(777), *etx.Sequence) - res, err := txStore.FindTxWithSequence(fromAddress, evmtypes.Nonce(777)) + res, err := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, evmtypes.Nonce(777)) require.NoError(t, err) assert.Equal(t, etx.Sequence, res.Sequence) }) @@ -727,7 +723,7 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("delete all receipts for eth transaction", func(t *testing.T) { etx := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 1) @@ -742,7 +738,7 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) { assert.Len(t, etx.TxAttempts[0].Receipts, 1) // use exported method - err = txStore.UpdateTxForRebroadcast(etx, attempt) + err = txStore.UpdateTxForRebroadcast(testutils.Context(t), etx, attempt) require.NoError(t, err) resultTx, err := txStore.FindTxWithAttempts(etx.ID) @@ -768,7 +764,7 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) head := evmtypes.Head{ Hash: utils.NewHash(), @@ -788,7 +784,7 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) { etx_8 := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 700, 8) etx_9 := cltest.MustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 777, 9) - etxes, err := txStore.FindTransactionsConfirmedInBlockRange(head.Number, 8, ethClient.ConfiguredChainID()) + etxes, err := txStore.FindTransactionsConfirmedInBlockRange(testutils.Context(t), head.Number, 8, ethClient.ConfiguredChainID()) require.NoError(t, err) assert.Len(t, etxes, 2) assert.Equal(t, etxes[0].Sequence, etx_8.Sequence) @@ -803,7 +799,7 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -811,7 +807,7 @@ func TestORM_SaveInsufficientEthAttempt(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) now := time.Now() - err = txStore.SaveInsufficientFundsAttempt(defaultDuration, &etx.TxAttempts[0], now) + err = txStore.SaveInsufficientFundsAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) attempt, err := txStore.FindTxAttempt(etx.TxAttempts[0].Hash) @@ -827,7 +823,7 @@ func TestORM_SaveSentAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -836,7 +832,7 @@ func TestORM_SaveSentAttempt(t *testing.T) { require.Nil(t, etx.BroadcastAt) now := time.Now() - err = txStore.SaveSentAttempt(defaultDuration, &etx.TxAttempts[0], now) + err = txStore.SaveSentAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) attempt, err := txStore.FindTxAttempt(etx.TxAttempts[0].Hash) @@ -852,7 +848,7 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) defaultDuration, err := time.ParseDuration("5s") require.NoError(t, err) @@ -860,7 +856,7 @@ func TestORM_SaveConfirmedMissingReceiptAttempt(t *testing.T) { etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptInProgress) now := time.Now() - err = txStore.SaveConfirmedMissingReceiptAttempt(context.Background(), defaultDuration, &etx.TxAttempts[0], now) + err = txStore.SaveConfirmedMissingReceiptAttempt(testutils.Context(t), defaultDuration, &etx.TxAttempts[0], now) require.NoError(t, err) etx, err := txStore.FindTxWithAttempts(etx.ID) @@ -877,7 +873,7 @@ func TestORM_DeleteInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("deletes in_progress attempt", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, fromAddress) @@ -899,7 +895,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("saves new in_progress attempt if attempt is new", func(t *testing.T) { etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress) @@ -907,7 +903,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) require.Equal(t, int64(0), attempt.ID) - err := txStore.SaveInProgressAttempt(&attempt) + err := txStore.SaveInProgressAttempt(testutils.Context(t), &attempt) require.NoError(t, err) attemptResult, err := txStore.FindTxAttempt(attempt.Hash) @@ -923,7 +919,7 @@ func TestORM_SaveInProgressAttempt(t *testing.T) { attempt.BroadcastBeforeBlockNum = nil attempt.State = txmgrtypes.TxAttemptInProgress - err := txStore.SaveInProgressAttempt(&attempt) + err := txStore.SaveInProgressAttempt(testutils.Context(t), &attempt) require.NoError(t, err) attemptResult, err := txStore.FindTxAttempt(attempt.Hash) @@ -941,13 +937,13 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) currentBlockNum := int64(10) t.Run("gets txs requiring gas bump", func(t *testing.T) { etx := cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptBroadcast) - err := txStore.SetBroadcastBeforeBlockNum(currentBlockNum, ethClient.ConfiguredChainID()) + err := txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), currentBlockNum, ethClient.ConfiguredChainID()) require.NoError(t, err) // this tx will require gas bump @@ -960,13 +956,13 @@ func TestORM_FindTxsRequiringGasBump(t *testing.T) { // this tx will not require gas bump cltest.MustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 2, fromAddress, txmgrtypes.TxAttemptBroadcast) - err = txStore.SetBroadcastBeforeBlockNum(currentBlockNum+1, ethClient.ConfiguredChainID()) + err = txStore.SetBroadcastBeforeBlockNum(testutils.Context(t), currentBlockNum+1, ethClient.ConfiguredChainID()) require.NoError(t, err) // any tx broadcast <= 10 will require gas bump newBlock := int64(12) gasBumpThreshold := int64(2) - etxs, err := txStore.FindTxsRequiringGasBump(context.Background(), fromAddress, newBlock, gasBumpThreshold, int64(0), ethClient.ConfiguredChainID()) + etxs, err := txStore.FindTxsRequiringGasBump(testutils.Context(t), fromAddress, newBlock, gasBumpThreshold, int64(0), ethClient.ConfiguredChainID()) require.NoError(t, err) assert.Len(t, etxs, 1) assert.Equal(t, etx.ID, etxs[0].ID) @@ -982,8 +978,8 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Insert order is mixed up to test sorting etx2 := cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 1, fromAddress) @@ -1000,7 +996,7 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherAddress) t.Run("returns all eth_txes with at least one attempt that is in insufficient_eth state", func(t *testing.T) { - etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(fromAddress, &cltest.FixtureChainID) + etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(testutils.Context(t), fromAddress, &cltest.FixtureChainID) require.NoError(t, err) assert.Len(t, etxs, 3) @@ -1014,7 +1010,7 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin }) t.Run("does not return eth_txes with different chain ID", func(t *testing.T) { - etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(fromAddress, big.NewInt(42)) + etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(testutils.Context(t), fromAddress, big.NewInt(42)) require.NoError(t, err) assert.Len(t, etxs, 0) @@ -1024,7 +1020,7 @@ func TestEthConfirmer_FindTxsRequiringResubmissionDueToInsufficientEth(t *testin pgtest.MustExec(t, db, `UPDATE evm.txes SET state='confirmed' WHERE id = $1`, etx1.ID) pgtest.MustExec(t, db, `UPDATE evm.txes SET state='fatal_error', nonce=NULL, error='foo', broadcast_at=NULL, initial_broadcast_at=NULL WHERE id = $1`, etx2.ID) - etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(fromAddress, &cltest.FixtureChainID) + etxs, err := txStore.FindTxsRequiringResubmissionDueToInsufficientFunds(testutils.Context(t), fromAddress, &cltest.FixtureChainID) require.NoError(t, err) assert.Len(t, etxs, 1) @@ -1042,14 +1038,14 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // tx state should be confirmed missing receipt // attempt should be broadcast before cutoff time t.Run("successfully mark errored transactions", func(t *testing.T) { etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) - err := txStore.MarkOldTxesMissingReceiptAsErrored(10, 2, ethClient.ConfiguredChainID()) + err := txStore.MarkOldTxesMissingReceiptAsErrored(testutils.Context(t), 10, 2, ethClient.ConfiguredChainID()) require.NoError(t, err) etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1058,14 +1054,8 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) { }) t.Run("successfully mark errored transactions w/ qopt passing in sql.Tx", func(t *testing.T) { - q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) - etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) - err := q.Transaction(func(q pg.Queryer) error { - err := txStore.MarkOldTxesMissingReceiptAsErrored(10, 2, ethClient.ConfiguredChainID(), pg.WithQueryer(q)) - require.NoError(t, err) - return nil - }) + err := txStore.MarkOldTxesMissingReceiptAsErrored(testutils.Context(t), 10, 2, ethClient.ConfiguredChainID()) require.NoError(t, err) // must run other query outside of postgres transaction so changes are committed @@ -1082,7 +1072,7 @@ func TestORM_LoadEthTxesAttempts(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("load eth tx attempt", func(t *testing.T) { etx := cltest.MustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress) @@ -1131,14 +1121,14 @@ func TestORM_SaveReplacementInProgressAttempt(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("replace eth tx attempt", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) oldAttempt := etx.TxAttempts[0] newAttempt := cltest.NewDynamicFeeEthTxAttempt(t, etx.ID) - err := txStore.SaveReplacementInProgressAttempt(oldAttempt, &newAttempt) + err := txStore.SaveReplacementInProgressAttempt(testutils.Context(t), oldAttempt, &newAttempt) require.NoError(t, err) etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1157,20 +1147,20 @@ func TestORM_FindNextUnstartedTransactionFromAddress(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("cannot find unstarted tx", func(t *testing.T) { cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) resultEtx := new(txmgr.Tx) - err := txStore.FindNextUnstartedTransactionFromAddress(resultEtx, fromAddress, ethClient.ConfiguredChainID()) + err := txStore.FindNextUnstartedTransactionFromAddress(testutils.Context(t), resultEtx, fromAddress, ethClient.ConfiguredChainID()) assert.ErrorIs(t, err, sql.ErrNoRows) }) t.Run("finds unstarted tx", func(t *testing.T) { cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) resultEtx := new(txmgr.Tx) - err := txStore.FindNextUnstartedTransactionFromAddress(resultEtx, fromAddress, ethClient.ConfiguredChainID()) + err := txStore.FindNextUnstartedTransactionFromAddress(testutils.Context(t), resultEtx, fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) }) } @@ -1183,14 +1173,14 @@ func TestORM_UpdateTxFatalError(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) etxPretendError := null.StringFrom("no more toilet paper") etx.Error = etxPretendError - err := txStore.UpdateTxFatalError(&etx) + err := txStore.UpdateTxFatalError(testutils.Context(t), &etx) require.NoError(t, err) etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) @@ -1206,7 +1196,7 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("update successful", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 13, fromAddress) @@ -1217,12 +1207,10 @@ func TestORM_UpdateTxAttemptInProgressToBroadcast(t *testing.T) { i := int16(0) etx.BroadcastAt = &time1 etx.InitialBroadcastAt = &time1 - err := txStore.UpdateTxAttemptInProgressToBroadcast(&etx, attempt, txmgrtypes.TxAttemptBroadcast, func(_ pg.Queryer) error { - // dummy function because tests do not use keystore as source of truth for next nonce number - i++ - return nil - }) + err := txStore.UpdateTxAttemptInProgressToBroadcast(testutils.Context(t), &etx, attempt, txmgrtypes.TxAttemptBroadcast) require.NoError(t, err) + // Increment sequence + i++ attemptResult, err := txStore.FindTxAttempt(attempt.Hash) require.NoError(t, err) @@ -1239,7 +1227,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) q := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) nonce := evmtypes.Nonce(123) @@ -1248,7 +1236,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { etx.Sequence = &nonce attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - err := txStore.UpdateTxUnstartedToInProgress(&etx, &attempt) + err := txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &attempt) require.NoError(t, err) etx, err = txStore.FindTxWithAttempts(etx.ID) @@ -1266,7 +1254,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { err := q.ExecQ("DELETE FROM evm.txes WHERE id = $1", etx.ID) require.NoError(t, err) - err = txStore.UpdateTxUnstartedToInProgress(&etx, &attempt) + err = txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &attempt) require.ErrorContains(t, err, "tx removed") }) @@ -1274,7 +1262,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { cfg = newTestChainScopedConfig(t) txStore = cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore = cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) q = pg.NewQ(db, logger.TestLogger(t), cfg.Database()) t.Run("update replaces abandoned tx with same hash", func(t *testing.T) { @@ -1303,11 +1291,11 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { // Even though this will initially fail due to idx_eth_tx_attempts_hash constraint, because the conflicting tx has been abandoned // it should succeed after removing the abandoned attempt and retrying the insert - err = txStore.UpdateTxUnstartedToInProgress(&etx2, &attempt2) + err = txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx2, &attempt2) require.NoError(t, err) }) - _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) // Same flow as previous test, but without calling txMgr.Abandon() t.Run("duplicate tx hash disallowed in tx_eth_attempts", func(t *testing.T) { @@ -1317,7 +1305,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { etx.State = txmgrcommon.TxUnstarted // Should fail due to idx_eth_tx_attempt_hash constraint - err := txStore.UpdateTxUnstartedToInProgress(&etx, &etx.TxAttempts[0]) + err := txStore.UpdateTxUnstartedToInProgress(testutils.Context(t), &etx, &etx.TxAttempts[0]) assert.ErrorContains(t, err, "idx_eth_tx_attempts_hash") txStore = cltest.NewTestTxStore(t, db, cfg.Database()) // current txStore is poisened now, next test will need fresh one }) @@ -1330,10 +1318,10 @@ func TestORM_GetTxInProgress(t *testing.T) { cfg := newTestChainScopedConfig(t) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("gets 0 in progress eth transaction", func(t *testing.T) { - etxResult, err := txStore.GetTxInProgress(fromAddress) + etxResult, err := txStore.GetTxInProgress(testutils.Context(t), fromAddress) require.NoError(t, err) require.Nil(t, etxResult) }) @@ -1341,7 +1329,7 @@ func TestORM_GetTxInProgress(t *testing.T) { t.Run("get 1 in progress eth transaction", func(t *testing.T) { etx := cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) - etxResult, err := txStore.GetTxInProgress(fromAddress) + etxResult, err := txStore.GetTxInProgress(testutils.Context(t), fromAddress) require.NoError(t, err) assert.Equal(t, etxResult.ID, etx.ID) }) @@ -1355,10 +1343,10 @@ func TestORM_HasInProgressTransaction(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("no in progress eth transaction", func(t *testing.T) { - exists, err := txStore.HasInProgressTransaction(fromAddress, ethClient.ConfiguredChainID()) + exists, err := txStore.HasInProgressTransaction(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) require.False(t, exists) }) @@ -1366,38 +1354,12 @@ func TestORM_HasInProgressTransaction(t *testing.T) { t.Run("has in progress eth transaction", func(t *testing.T) { cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 123, fromAddress) - exists, err := txStore.HasInProgressTransaction(fromAddress, ethClient.ConfiguredChainID()) + exists, err := txStore.HasInProgressTransaction(testutils.Context(t), fromAddress, ethClient.ConfiguredChainID()) require.NoError(t, err) require.True(t, exists) }) } -func TestORM_UpdateEthKeyNextNonce(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := newTestChainScopedConfig(t) - txStore := cltest.NewTxStore(t, db, cfg.Database()) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyState, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) - - t.Run("update next nonce", func(t *testing.T) { - assert.Equal(t, int64(0), ethKeyState.NextNonce) - err := txStore.UpdateKeyNextSequence(evmtypes.Nonce(24), evmtypes.Nonce(0), fromAddress, ethClient.ConfiguredChainID()) - require.NoError(t, err) - - newNextNonce, err := ethKeyStore.NextSequence(fromAddress, ethClient.ConfiguredChainID()) - require.NoError(t, err) - assert.Equal(t, int64(24), newNextNonce.Int64()) - }) - - t.Run("no rows found", func(t *testing.T) { - err := txStore.UpdateKeyNextSequence(evmtypes.Nonce(100), evmtypes.Nonce(123), fromAddress, ethClient.ConfiguredChainID()) - require.Error(t, err) - }) -} - func TestORM_CountUnconfirmedTransactions(t *testing.T) { t.Parallel() @@ -1406,15 +1368,15 @@ func TestORM_CountUnconfirmedTransactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, otherAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) - count, err := txStore.CountUnconfirmedTransactions(fromAddress, &cltest.FixtureChainID) + count, err := txStore.CountUnconfirmedTransactions(testutils.Context(t), fromAddress, &cltest.FixtureChainID) require.NoError(t, err) assert.Equal(t, int(count), 3) } @@ -1427,15 +1389,15 @@ func TestORM_CountUnstartedTransactions(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) cltest.MustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) cltest.MustCreateUnstartedGeneratedTx(t, txStore, otherAddress, &cltest.FixtureChainID) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) - count, err := txStore.CountUnstartedTransactions(fromAddress, &cltest.FixtureChainID) + count, err := txStore.CountUnstartedTransactions(testutils.Context(t), fromAddress, &cltest.FixtureChainID) require.NoError(t, err) assert.Equal(t, int(count), 2) } @@ -1448,8 +1410,8 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - _, otherAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) toAddress := testutils.NewAddress() encodedPayload := []byte{1, 2, 3} @@ -1458,7 +1420,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { var maxUnconfirmedTransactions uint64 = 2 t.Run("with no eth_txes returns nil", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.NoError(t, err) }) @@ -1468,7 +1430,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { } t.Run("with eth_txes from another address returns nil", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.NoError(t, err) }) @@ -1477,7 +1439,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { } t.Run("ignores fatally_errored transactions", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.NoError(t, err) }) @@ -1488,7 +1450,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { n++ t.Run("unconfirmed and in_progress transactions do not count", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, 1, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, 1, &cltest.FixtureChainID) require.NoError(t, err) }) @@ -1499,7 +1461,7 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { } t.Run("with many confirmed eth_txes from the same address returns nil", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.NoError(t, err) }) @@ -1508,30 +1470,30 @@ func TestORM_CheckTxQueueCapacity(t *testing.T) { } t.Run("with fewer unstarted eth_txes than limit returns nil", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.NoError(t, err) }) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) t.Run("with equal or more unstarted eth_txes than limit returns error", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("cannot create transaction; too many unstarted transactions in the queue (2/%d). WARNING: Hitting EVM.Transactions.MaxQueued", maxUnconfirmedTransactions)) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, feeLimit, value, &cltest.FixtureChainID) - err = txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) + err = txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, &cltest.FixtureChainID) require.Error(t, err) require.Contains(t, err.Error(), fmt.Sprintf("cannot create transaction; too many unstarted transactions in the queue (3/%d). WARNING: Hitting EVM.Transactions.MaxQueued", maxUnconfirmedTransactions)) }) t.Run("with different chain ID ignores txes", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, maxUnconfirmedTransactions, big.NewInt(42)) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, maxUnconfirmedTransactions, big.NewInt(42)) require.NoError(t, err) }) t.Run("disables check with 0 limit", func(t *testing.T) { - err := txStore.CheckTxQueueCapacity(fromAddress, 0, &cltest.FixtureChainID) + err := txStore.CheckTxQueueCapacity(testutils.Context(t), fromAddress, 0, &cltest.FixtureChainID) require.NoError(t, err) }) } @@ -1544,7 +1506,7 @@ func TestORM_CreateTransaction(t *testing.T) { txStore := cltest.NewTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() gasLimit := uint32(1000) payload := []byte{1, 2, 3} @@ -1555,8 +1517,8 @@ func TestORM_CreateTransaction(t *testing.T) { subject := uuid.New() strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{UUID: subject, Valid: true}) - strategy.On("PruneQueue", mock.AnythingOfType("*txmgr.evmTxStore"), mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) - etx, err := txStore.CreateTransaction(txmgr.TxRequest{ + strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("*txmgr.evmTxStore")).Return(int64(0), nil) + etx, err := txStore.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -1599,10 +1561,10 @@ func TestORM_CreateTransaction(t *testing.T) { PipelineTaskRunID: &id, Strategy: txmgrcommon.NewSendEveryStrategy(), } - tx1, err := txStore.CreateTransaction(txRequest, ethClient.ConfiguredChainID()) + tx1, err := txStore.CreateTransaction(testutils.Context(t), txRequest, ethClient.ConfiguredChainID()) assert.NoError(t, err) - tx2, err := txStore.CreateTransaction(txRequest, ethClient.ConfiguredChainID()) + tx2, err := txStore.CreateTransaction(testutils.Context(t), txRequest, ethClient.ConfiguredChainID()) assert.NoError(t, err) assert.Equal(t, tx1.GetID(), tx2.GetID()) @@ -1617,7 +1579,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { txStore := cltest.NewTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() evmtest.NewEthClientMockWithDefaultChain(t) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) t.Run("does not prune if queue has not exceeded capacity", func(t *testing.T) { subject1 := uuid.New() diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index b4570484d0d..d6f961ccb50 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -82,13 +82,12 @@ func (_m *Config) RPCDefaultBatchSize() uint32 { return r0 } -type mockConstructorTestingTNewConfig interface { +// NewConfig creates a new instance of Config. 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 NewConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { +}) *Config { mock := &Config{} mock.Mock.Test(t) diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index 4a06741a2f3..69a0d257f7a 100644 --- a/core/chains/evm/txmgr/mocks/evm_tx_store.go +++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -14,8 +14,6 @@ import ( mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - time "time" types "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -28,13 +26,13 @@ type EvmTxStore struct { mock.Mock } -// Abandon provides a mock function with given fields: id, addr -func (_m *EvmTxStore) Abandon(id *big.Int, addr common.Address) error { - ret := _m.Called(id, addr) +// Abandon provides a mock function with given fields: ctx, id, addr +func (_m *EvmTxStore) Abandon(ctx context.Context, id *big.Int, addr common.Address) error { + ret := _m.Called(ctx, id, addr) var r0 error - if rf, ok := ret.Get(0).(func(*big.Int, common.Address) error); ok { - r0 = rf(id, addr) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, common.Address) error); ok { + r0 = rf(ctx, id, addr) } else { r0 = ret.Error(0) } @@ -42,20 +40,13 @@ func (_m *EvmTxStore) Abandon(id *big.Int, addr common.Address) error { return r0 } -// CheckTxQueueCapacity provides a mock function with given fields: fromAddress, maxQueuedTransactions, chainID, qopts -func (_m *EvmTxStore) CheckTxQueueCapacity(fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, maxQueuedTransactions, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CheckTxQueueCapacity provides a mock function with given fields: ctx, fromAddress, maxQueuedTransactions, chainID +func (_m *EvmTxStore) CheckTxQueueCapacity(ctx context.Context, fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int) error { + ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) var r0 error - if rf, ok := ret.Get(0).(func(common.Address, uint64, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(fromAddress, maxQueuedTransactions, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint64, *big.Int) error); ok { + r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) } else { r0 = ret.Error(0) } @@ -68,30 +59,23 @@ func (_m *EvmTxStore) Close() { _m.Called() } -// CountUnconfirmedTransactions provides a mock function with given fields: fromAddress, chainID, qopts -func (_m *EvmTxStore) CountUnconfirmedTransactions(fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) (uint32, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CountUnconfirmedTransactions provides a mock function with given fields: ctx, fromAddress, chainID +func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { + ret := _m.Called(ctx, fromAddress, chainID) var r0 uint32 var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) (uint32, error)); ok { - return rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { + return rf(ctx, fromAddress, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) uint32); ok { - r0 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) uint32); ok { + r0 = rf(ctx, fromAddress, chainID) } else { r0 = ret.Get(0).(uint32) } - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, chainID) } else { r1 = ret.Error(1) } @@ -99,30 +83,23 @@ func (_m *EvmTxStore) CountUnconfirmedTransactions(fromAddress common.Address, c return r0, r1 } -// CountUnstartedTransactions provides a mock function with given fields: fromAddress, chainID, qopts -func (_m *EvmTxStore) CountUnstartedTransactions(fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) (uint32, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CountUnstartedTransactions provides a mock function with given fields: ctx, fromAddress, chainID +func (_m *EvmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { + ret := _m.Called(ctx, fromAddress, chainID) var r0 uint32 var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) (uint32, error)); ok { - return rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { + return rf(ctx, fromAddress, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) uint32); ok { - r0 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) uint32); ok { + r0 = rf(ctx, fromAddress, chainID) } else { r0 = ret.Get(0).(uint32) } - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, chainID) } else { r1 = ret.Error(1) } @@ -130,30 +107,23 @@ func (_m *EvmTxStore) CountUnstartedTransactions(fromAddress common.Address, cha return r0, r1 } -// CreateTransaction provides a mock function with given fields: txRequest, chainID, qopts -func (_m *EvmTxStore) CreateTransaction(txRequest types.TxRequest[common.Address, common.Hash], chainID *big.Int, qopts ...pg.QOpt) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, txRequest, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// CreateTransaction provides a mock function with given fields: ctx, txRequest, chainID +func (_m *EvmTxStore) CreateTransaction(ctx context.Context, txRequest types.TxRequest[common.Address, common.Hash], chainID *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, txRequest, chainID) var r0 types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(types.TxRequest[common.Address, common.Hash], *big.Int, ...pg.QOpt) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, types.TxRequest[common.Address, common.Hash], *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, txRequest, chainID) } - if rf, ok := ret.Get(0).(func(types.TxRequest[common.Address, common.Hash], *big.Int, ...pg.QOpt) types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, types.TxRequest[common.Address, common.Hash], *big.Int) types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, txRequest, chainID) } else { r0 = ret.Get(0).(types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } - if rf, ok := ret.Get(1).(func(types.TxRequest[common.Address, common.Hash], *big.Int, ...pg.QOpt) error); ok { - r1 = rf(txRequest, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, types.TxRequest[common.Address, common.Hash], *big.Int) error); ok { + r1 = rf(ctx, txRequest, chainID) } else { r1 = ret.Error(1) } @@ -175,20 +145,37 @@ func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types return r0 } -// FindNextUnstartedTransactionFromAddress provides a mock function with given fields: etx, fromAddress, chainID, qopts -func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], fromAddress common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] +// FindLatestSequence provides a mock function with given fields: ctx, fromAddress, chainId +func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (evmtypes.Nonce, error) { + ret := _m.Called(ctx, fromAddress, chainId) + + var r0 evmtypes.Nonce + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { + return rf(ctx, fromAddress, chainId) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) evmtypes.Nonce); ok { + r0 = rf(ctx, fromAddress, chainId) + } else { + r0 = ret.Get(0).(evmtypes.Nonce) + } + + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, fromAddress, chainId) + } else { + r1 = ret.Error(1) } - var _ca []interface{} - _ca = append(_ca, etx, fromAddress, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) + + return r0, r1 +} + +// FindNextUnstartedTransactionFromAddress provides a mock function with given fields: ctx, etx, fromAddress, chainID +func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], fromAddress common.Address, chainID *big.Int) error { + ret := _m.Called(ctx, etx, fromAddress, chainID) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(etx, fromAddress, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], common.Address, *big.Int) error); ok { + r0 = rf(ctx, etx, fromAddress, chainID) } else { r0 = ret.Error(0) } @@ -222,25 +209,25 @@ func (_m *EvmTxStore) FindReceiptsPendingConfirmation(ctx context.Context, block return r0, r1 } -// FindTransactionsConfirmedInBlockRange provides a mock function with given fields: highBlockNumber, lowBlockNumber, chainID -func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(highBlockNumber int64, lowBlockNumber int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(highBlockNumber, lowBlockNumber, chainID) +// FindTransactionsConfirmedInBlockRange provides a mock function with given fields: ctx, highBlockNumber, lowBlockNumber, chainID +func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, highBlockNumber, lowBlockNumber, chainID) } - if rf, ok := ret.Get(0).(func(int64, int64, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, highBlockNumber, lowBlockNumber, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(int64, int64, *big.Int) error); ok { - r1 = rf(highBlockNumber, lowBlockNumber, chainID) + if rf, ok := ret.Get(1).(func(context.Context, int64, int64, *big.Int) error); ok { + r1 = rf(ctx, highBlockNumber, lowBlockNumber, chainID) } else { r1 = ret.Error(1) } @@ -300,25 +287,25 @@ func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAtte return r0, r1 } -// FindTxAttemptsConfirmedMissingReceipt provides a mock function with given fields: chainID -func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(chainID) +// FindTxAttemptsConfirmedMissingReceipt provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, chainID) var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -326,25 +313,25 @@ func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(chainID *big.Int) ([ return r0, r1 } -// FindTxAttemptsRequiringReceiptFetch provides a mock function with given fields: chainID -func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(chainID) +// FindTxAttemptsRequiringReceiptFetch provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, chainID) var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(*big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, chainID) } - if rf, ok := ret.Get(0).(func(*big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(*big.Int) error); ok { - r1 = rf(chainID) + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, chainID) } else { r1 = ret.Error(1) } @@ -352,25 +339,25 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(chainID *big.Int) ([]t return r0, r1 } -// FindTxAttemptsRequiringResend provides a mock function with given fields: olderThan, maxInFlightTransactions, chainID, address -func (_m *EvmTxStore) FindTxAttemptsRequiringResend(olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(olderThan, maxInFlightTransactions, chainID, address) +// FindTxAttemptsRequiringResend provides a mock function with given fields: ctx, olderThan, maxInFlightTransactions, chainID, address +func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(time.Time, uint32, *big.Int, common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, *big.Int, common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } - if rf, ok := ret.Get(0).(func(time.Time, uint32, *big.Int, common.Address) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, uint32, *big.Int, common.Address) []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(time.Time, uint32, *big.Int, common.Address) error); ok { - r1 = rf(olderThan, maxInFlightTransactions, chainID, address) + if rf, ok := ret.Get(1).(func(context.Context, time.Time, uint32, *big.Int, common.Address) error); ok { + r1 = rf(ctx, olderThan, maxInFlightTransactions, chainID, address) } else { r1 = ret.Error(1) } @@ -428,25 +415,25 @@ func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common return r0, r1 } -// FindTxWithIdempotencyKey provides a mock function with given fields: idempotencyKey, chainID -func (_m *EvmTxStore) FindTxWithIdempotencyKey(idempotencyKey string, chainID *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(idempotencyKey, chainID) +// FindTxWithIdempotencyKey provides a mock function with given fields: ctx, idempotencyKey, chainID +func (_m *EvmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, idempotencyKey, chainID) var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(string, *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(idempotencyKey, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, idempotencyKey, chainID) } - if rf, ok := ret.Get(0).(func(string, *big.Int) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(idempotencyKey, chainID) + if rf, ok := ret.Get(0).(func(context.Context, string, *big.Int) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, idempotencyKey, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(string, *big.Int) error); ok { - r1 = rf(idempotencyKey, chainID) + if rf, ok := ret.Get(1).(func(context.Context, string, *big.Int) error); ok { + r1 = rf(ctx, idempotencyKey, chainID) } else { r1 = ret.Error(1) } @@ -454,25 +441,25 @@ func (_m *EvmTxStore) FindTxWithIdempotencyKey(idempotencyKey string, chainID *b return r0, r1 } -// FindTxWithSequence provides a mock function with given fields: fromAddress, seq -func (_m *EvmTxStore) FindTxWithSequence(fromAddress common.Address, seq evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - ret := _m.Called(fromAddress, seq) +// FindTxWithSequence provides a mock function with given fields: ctx, fromAddress, seq +func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common.Address, seq evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, fromAddress, seq) var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(common.Address, evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(fromAddress, seq) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, fromAddress, seq) } - if rf, ok := ret.Get(0).(func(common.Address, evmtypes.Nonce) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(fromAddress, seq) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, evmtypes.Nonce) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, fromAddress, seq) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(common.Address, evmtypes.Nonce) error); ok { - r1 = rf(fromAddress, seq) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, evmtypes.Nonce) error); ok { + r1 = rf(ctx, fromAddress, seq) } else { r1 = ret.Error(1) } @@ -506,32 +493,25 @@ func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address commo return r0, r1 } -// FindTxsRequiringResubmissionDueToInsufficientFunds provides a mock function with given fields: address, chainID, qopts -func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(address common.Address, chainID *big.Int, qopts ...pg.QOpt) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// FindTxsRequiringResubmissionDueToInsufficientFunds provides a mock function with given fields: ctx, address, chainID +func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address common.Address, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, address, chainID) var r0 []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, address, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) []*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, address, chainID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, address, chainID) } else { r1 = ret.Error(1) } @@ -565,32 +545,25 @@ func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address commo return r0, r1 } -// GetTxInProgress provides a mock function with given fields: fromAddress, qopts -func (_m *EvmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QOpt) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, fromAddress) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// GetTxInProgress provides a mock function with given fields: ctx, fromAddress +func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { + ret := _m.Called(ctx, fromAddress) var r0 *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 error - if rf, ok := ret.Get(0).(func(common.Address, ...pg.QOpt) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { - return rf(fromAddress, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { + return rf(ctx, fromAddress) } - if rf, ok := ret.Get(0).(func(common.Address, ...pg.QOpt) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { - r0 = rf(fromAddress, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address) *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { + r0 = rf(ctx, fromAddress) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) } } - if rf, ok := ret.Get(1).(func(common.Address, ...pg.QOpt) error); ok { - r1 = rf(fromAddress, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { + r1 = rf(ctx, fromAddress) } else { r1 = ret.Error(1) } @@ -598,30 +571,23 @@ func (_m *EvmTxStore) GetTxInProgress(fromAddress common.Address, qopts ...pg.QO return r0, r1 } -// HasInProgressTransaction provides a mock function with given fields: account, chainID, qopts -func (_m *EvmTxStore) HasInProgressTransaction(account common.Address, chainID *big.Int, qopts ...pg.QOpt) (bool, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, account, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// HasInProgressTransaction provides a mock function with given fields: ctx, account, chainID +func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account common.Address, chainID *big.Int) (bool, error) { + ret := _m.Called(ctx, account, chainID) var r0 bool var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) (bool, error)); ok { - return rf(account, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (bool, error)); ok { + return rf(ctx, account, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) bool); ok { - r0 = rf(account, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) bool); ok { + r0 = rf(ctx, account, chainID) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(account, chainID, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, common.Address, *big.Int) error); ok { + r1 = rf(ctx, account, chainID) } else { r1 = ret.Error(1) } @@ -629,20 +595,13 @@ func (_m *EvmTxStore) HasInProgressTransaction(account common.Address, chainID * return r0, r1 } -// LoadTxAttempts provides a mock function with given fields: etx, qopts -func (_m *EvmTxStore) LoadTxAttempts(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// LoadTxAttempts provides a mock function with given fields: ctx, etx +func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, etx) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], ...pg.QOpt) error); ok { - r0 = rf(etx, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, etx) } else { r0 = ret.Error(0) } @@ -650,13 +609,13 @@ func (_m *EvmTxStore) LoadTxAttempts(etx *types.Tx[*big.Int, common.Address, com return r0 } -// MarkAllConfirmedMissingReceipt provides a mock function with given fields: chainID -func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(chainID *big.Int) error { - ret := _m.Called(chainID) +// MarkAllConfirmedMissingReceipt provides a mock function with given fields: ctx, chainID +func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) error { + ret := _m.Called(ctx, chainID) var r0 error - if rf, ok := ret.Get(0).(func(*big.Int) error); ok { - r0 = rf(chainID) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) error); ok { + r0 = rf(ctx, chainID) } else { r0 = ret.Error(0) } @@ -664,20 +623,13 @@ func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(chainID *big.Int) error { return r0 } -// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: blockNum, finalityDepth, chainID, qopts -func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(blockNum int64, finalityDepth uint32, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, blockNum, finalityDepth, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, finalityDepth, chainID +func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error { + ret := _m.Called(ctx, blockNum, finalityDepth, chainID) var r0 error - if rf, ok := ret.Get(0).(func(int64, uint32, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(blockNum, finalityDepth, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, *big.Int) error); ok { + r0 = rf(ctx, blockNum, finalityDepth, chainID) } else { r0 = ret.Error(0) } @@ -685,20 +637,13 @@ func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(blockNum int64, finalit return r0 } -// PreloadTxes provides a mock function with given fields: attempts, qopts -func (_m *EvmTxStore) PreloadTxes(attempts []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, attempts) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// PreloadTxes provides a mock function with given fields: ctx, attempts +func (_m *EvmTxStore) PreloadTxes(ctx context.Context, attempts []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, attempts) var r0 error - if rf, ok := ret.Get(0).(func([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], ...pg.QOpt) error); ok { - r0 = rf(attempts, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, attempts) } else { r0 = ret.Error(0) } @@ -706,30 +651,23 @@ func (_m *EvmTxStore) PreloadTxes(attempts []types.TxAttempt[*big.Int, common.Ad return r0 } -// PruneUnstartedTxQueue provides a mock function with given fields: queueSize, subject, qopts -func (_m *EvmTxStore) PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, qopts ...pg.QOpt) (int64, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, queueSize, subject) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// PruneUnstartedTxQueue provides a mock function with given fields: ctx, queueSize, subject +func (_m *EvmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { + ret := _m.Called(ctx, queueSize, subject) var r0 int64 var r1 error - if rf, ok := ret.Get(0).(func(uint32, uuid.UUID, ...pg.QOpt) (int64, error)); ok { - return rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { + return rf(ctx, queueSize, subject) } - if rf, ok := ret.Get(0).(func(uint32, uuid.UUID, ...pg.QOpt) int64); ok { - r0 = rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) int64); ok { + r0 = rf(ctx, queueSize, subject) } else { r0 = ret.Get(0).(int64) } - if rf, ok := ret.Get(1).(func(uint32, uuid.UUID, ...pg.QOpt) error); ok { - r1 = rf(queueSize, subject, qopts...) + if rf, ok := ret.Get(1).(func(context.Context, uint32, uuid.UUID) error); ok { + r1 = rf(ctx, queueSize, subject) } else { r1 = ret.Error(1) } @@ -737,13 +675,13 @@ func (_m *EvmTxStore) PruneUnstartedTxQueue(queueSize uint32, subject uuid.UUID, return r0, r1 } -// ReapTxHistory provides a mock function with given fields: minBlockNumberToKeep, timeThreshold, chainID -func (_m *EvmTxStore) ReapTxHistory(minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { - ret := _m.Called(minBlockNumberToKeep, timeThreshold, chainID) +// ReapTxHistory provides a mock function with given fields: ctx, minBlockNumberToKeep, timeThreshold, chainID +func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { + ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) var r0 error - if rf, ok := ret.Get(0).(func(int64, time.Time, *big.Int) error); ok { - r0 = rf(minBlockNumberToKeep, timeThreshold, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, *big.Int) error); ok { + r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) } else { r0 = ret.Error(0) } @@ -765,13 +703,13 @@ func (_m *EvmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, ti return r0 } -// SaveFetchedReceipts provides a mock function with given fields: receipts, chainID -func (_m *EvmTxStore) SaveFetchedReceipts(receipts []*evmtypes.Receipt, chainID *big.Int) error { - ret := _m.Called(receipts, chainID) +// SaveFetchedReceipts provides a mock function with given fields: ctx, receipts, chainID +func (_m *EvmTxStore) SaveFetchedReceipts(ctx context.Context, receipts []*evmtypes.Receipt, chainID *big.Int) error { + ret := _m.Called(ctx, receipts, chainID) var r0 error - if rf, ok := ret.Get(0).(func([]*evmtypes.Receipt, *big.Int) error); ok { - r0 = rf(receipts, chainID) + if rf, ok := ret.Get(0).(func(context.Context, []*evmtypes.Receipt, *big.Int) error); ok { + r0 = rf(ctx, receipts, chainID) } else { r0 = ret.Error(0) } @@ -779,13 +717,13 @@ func (_m *EvmTxStore) SaveFetchedReceipts(receipts []*evmtypes.Receipt, chainID return r0 } -// SaveInProgressAttempt provides a mock function with given fields: attempt -func (_m *EvmTxStore) SaveInProgressAttempt(attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { - ret := _m.Called(attempt) +// SaveInProgressAttempt provides a mock function with given fields: ctx, attempt +func (_m *EvmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, attempt) var r0 error - if rf, ok := ret.Get(0).(func(*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { - r0 = rf(attempt) + if rf, ok := ret.Get(0).(func(context.Context, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, attempt) } else { r0 = ret.Error(0) } @@ -793,13 +731,13 @@ func (_m *EvmTxStore) SaveInProgressAttempt(attempt *types.TxAttempt[*big.Int, c return r0 } -// SaveInsufficientFundsAttempt provides a mock function with given fields: timeout, attempt, broadcastAt -func (_m *EvmTxStore) SaveInsufficientFundsAttempt(timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { - ret := _m.Called(timeout, attempt, broadcastAt) +// SaveInsufficientFundsAttempt provides a mock function with given fields: ctx, timeout, attempt, broadcastAt +func (_m *EvmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { + ret := _m.Called(ctx, timeout, attempt, broadcastAt) var r0 error - if rf, ok := ret.Get(0).(func(time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { - r0 = rf(timeout, attempt, broadcastAt) + if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { + r0 = rf(ctx, timeout, attempt, broadcastAt) } else { r0 = ret.Error(0) } @@ -807,20 +745,13 @@ func (_m *EvmTxStore) SaveInsufficientFundsAttempt(timeout time.Duration, attemp return r0 } -// SaveReplacementInProgressAttempt provides a mock function with given fields: oldAttempt, replacementAttempt, qopts -func (_m *EvmTxStore) SaveReplacementInProgressAttempt(oldAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], replacementAttempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, oldAttempt, replacementAttempt) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// SaveReplacementInProgressAttempt provides a mock function with given fields: ctx, oldAttempt, replacementAttempt +func (_m *EvmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], replacementAttempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, oldAttempt, replacementAttempt) var r0 error - if rf, ok := ret.Get(0).(func(types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], ...pg.QOpt) error); ok { - r0 = rf(oldAttempt, replacementAttempt, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, oldAttempt, replacementAttempt) } else { r0 = ret.Error(0) } @@ -828,13 +759,13 @@ func (_m *EvmTxStore) SaveReplacementInProgressAttempt(oldAttempt types.TxAttemp return r0 } -// SaveSentAttempt provides a mock function with given fields: timeout, attempt, broadcastAt -func (_m *EvmTxStore) SaveSentAttempt(timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { - ret := _m.Called(timeout, attempt, broadcastAt) +// SaveSentAttempt provides a mock function with given fields: ctx, timeout, attempt, broadcastAt +func (_m *EvmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { + ret := _m.Called(ctx, timeout, attempt, broadcastAt) var r0 error - if rf, ok := ret.Get(0).(func(time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { - r0 = rf(timeout, attempt, broadcastAt) + if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { + r0 = rf(ctx, timeout, attempt, broadcastAt) } else { r0 = ret.Error(0) } @@ -842,13 +773,13 @@ func (_m *EvmTxStore) SaveSentAttempt(timeout time.Duration, attempt *types.TxAt return r0 } -// SetBroadcastBeforeBlockNum provides a mock function with given fields: blockNum, chainID -func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(blockNum int64, chainID *big.Int) error { - ret := _m.Called(blockNum, chainID) +// SetBroadcastBeforeBlockNum provides a mock function with given fields: ctx, blockNum, chainID +func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID *big.Int) error { + ret := _m.Called(ctx, blockNum, chainID) var r0 error - if rf, ok := ret.Get(0).(func(int64, *big.Int) error); ok { - r0 = rf(blockNum, chainID) + if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) error); ok { + r0 = rf(ctx, blockNum, chainID) } else { r0 = ret.Error(0) } @@ -955,13 +886,13 @@ func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big. return r0, r1, r2 } -// UpdateBroadcastAts provides a mock function with given fields: now, etxIDs -func (_m *EvmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { - ret := _m.Called(now, etxIDs) +// UpdateBroadcastAts provides a mock function with given fields: ctx, now, etxIDs +func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { + ret := _m.Called(ctx, now, etxIDs) var r0 error - if rf, ok := ret.Get(0).(func(time.Time, []int64) error); ok { - r0 = rf(now, etxIDs) + if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { + r0 = rf(ctx, now, etxIDs) } else { r0 = ret.Error(0) } @@ -969,20 +900,13 @@ func (_m *EvmTxStore) UpdateBroadcastAts(now time.Time, etxIDs []int64) error { return r0 } -// UpdateKeyNextSequence provides a mock function with given fields: newNextSequence, currentNextSequence, address, chainID, qopts -func (_m *EvmTxStore) UpdateKeyNextSequence(newNextSequence evmtypes.Nonce, currentNextSequence evmtypes.Nonce, address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, newNextSequence, currentNextSequence, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: ctx, etx, attempt, NewAttemptState +func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState) error { + ret := _m.Called(ctx, etx, attempt, NewAttemptState) var r0 error - if rf, ok := ret.Get(0).(func(evmtypes.Nonce, evmtypes.Nonce, common.Address, *big.Int, ...pg.QOpt) error); ok { - r0 = rf(newNextSequence, currentNextSequence, address, chainID, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState) error); ok { + r0 = rf(ctx, etx, attempt, NewAttemptState) } else { r0 = ret.Error(0) } @@ -990,20 +914,13 @@ func (_m *EvmTxStore) UpdateKeyNextSequence(newNextSequence evmtypes.Nonce, curr return r0 } -// UpdateTxAttemptInProgressToBroadcast provides a mock function with given fields: etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts -func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState, incrNextSequenceCallback func(pg.Queryer) error, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt, NewAttemptState, incrNextSequenceCallback) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxFatalError provides a mock function with given fields: ctx, etx +func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, etx) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState, func(pg.Queryer) error, ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, NewAttemptState, incrNextSequenceCallback, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, etx) } else { r0 = ret.Error(0) } @@ -1011,20 +928,13 @@ func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(etx *types.Tx[*big.In return r0 } -// UpdateTxFatalError provides a mock function with given fields: etx, qopts -func (_m *EvmTxStore) UpdateTxFatalError(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxForRebroadcast provides a mock function with given fields: ctx, etx, etxAttempt +func (_m *EvmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], etxAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, etx, etxAttempt) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], ...pg.QOpt) error); ok { - r0 = rf(etx, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, etx, etxAttempt) } else { r0 = ret.Error(0) } @@ -1032,13 +942,13 @@ func (_m *EvmTxStore) UpdateTxFatalError(etx *types.Tx[*big.Int, common.Address, return r0 } -// UpdateTxForRebroadcast provides a mock function with given fields: etx, etxAttempt -func (_m *EvmTxStore) UpdateTxForRebroadcast(etx types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], etxAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { - ret := _m.Called(etx, etxAttempt) +// UpdateTxUnstartedToInProgress provides a mock function with given fields: ctx, etx, attempt +func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { + ret := _m.Called(ctx, etx, attempt) var r0 error - if rf, ok := ret.Get(0).(func(types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { - r0 = rf(etx, etxAttempt) + if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { + r0 = rf(ctx, etx, attempt) } else { r0 = ret.Error(0) } @@ -1046,20 +956,13 @@ func (_m *EvmTxStore) UpdateTxForRebroadcast(etx types.Tx[*big.Int, common.Addre return r0 } -// UpdateTxUnstartedToInProgress provides a mock function with given fields: etx, attempt, qopts -func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, etx, attempt) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) +// UpdateTxsUnconfirmed provides a mock function with given fields: ctx, ids +func (_m *EvmTxStore) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { + ret := _m.Called(ctx, ids) var r0 error - if rf, ok := ret.Get(0).(func(*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], ...pg.QOpt) error); ok { - r0 = rf(etx, attempt, qopts...) + if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { + r0 = rf(ctx, ids) } else { r0 = ret.Error(0) } @@ -1067,27 +970,12 @@ func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(etx *types.Tx[*big.Int, comm return r0 } -// UpdateTxsUnconfirmed provides a mock function with given fields: ids -func (_m *EvmTxStore) UpdateTxsUnconfirmed(ids []int64) error { - ret := _m.Called(ids) - - var r0 error - if rf, ok := ret.Get(0).(func([]int64) error); ok { - r0 = rf(ids) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -type mockConstructorTestingTNewEvmTxStore interface { +// NewEvmTxStore creates a new instance of EvmTxStore. 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 NewEvmTxStore(t interface { mock.TestingT Cleanup(func()) -} - -// NewEvmTxStore creates a new instance of EvmTxStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewEvmTxStore(t mockConstructorTestingTNewEvmTxStore) *EvmTxStore { +}) *EvmTxStore { mock := &EvmTxStore{} mock.Mock.Test(t) diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index e87c54c2a3f..9044c52c9ae 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -25,7 +25,7 @@ type ( TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int, evmtypes.Nonce] TxAttemptBuilder = txmgrtypes.TxAttemptBuilder[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - NonceSyncer = txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash] + NonceSyncer = txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, evmtypes.Nonce] TransmitCheckerFactory = txmgr.TransmitCheckerFactory[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] Txm = txmgr.Txm[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TxManager = txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] diff --git a/core/chains/evm/txmgr/nonce_syncer.go b/core/chains/evm/txmgr/nonce_syncer.go index d057ff0e74a..dc0d27e6414 100644 --- a/core/chains/evm/txmgr/nonce_syncer.go +++ b/core/chains/evm/txmgr/nonce_syncer.go @@ -10,9 +10,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/txmgr" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) // NonceSyncer manages the delicate task of syncing the local nonce with the @@ -22,7 +21,7 @@ import ( // it to our local value. // // Usually the on-chain nonce will be the same as (or lower than) the -// next_nonce in the DB, in which case we do nothing. +// highest sequence in the DB, in which case we do nothing. // // If we are restoring from a backup however, or another wallet has used the // account, the chain nonce might be higher than our local one. In this @@ -47,14 +46,13 @@ import ( // // This gives us re-org protection up to EVM.FinalityDepth deep in the // worst case, which is in line with our other guarantees. -var _ txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash] = &nonceSyncerImpl{} +var _ txmgr.SequenceSyncer[common.Address, common.Hash, common.Hash, types.Nonce] = &nonceSyncerImpl{} type nonceSyncerImpl struct { txStore EvmTxStore client TxmClient chainID *big.Int logger logger.Logger - kst KeyStore } // NewNonceSyncer returns a new syncer @@ -62,7 +60,6 @@ func NewNonceSyncer( txStore EvmTxStore, lggr logger.Logger, ethClient evmclient.Client, - kst KeyStore, ) NonceSyncer { lggr = lggr.Named("NonceSyncer") return &nonceSyncerImpl{ @@ -70,7 +67,6 @@ func NewNonceSyncer( client: NewEvmTxmClient(ethClient), chainID: ethClient.ConfiguredChainID(), logger: lggr, - kst: kst, } } @@ -78,64 +74,33 @@ func NewNonceSyncer( // // This should only be called once, before the EthBroadcaster has started. // Calling it later is not safe and could lead to races. -func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address) (err error) { - err = s.fastForwardNonceIfNecessary(ctx, addr) - return errors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") +func (s nonceSyncerImpl) Sync(ctx context.Context, addr common.Address, localNonce types.Nonce) (nonce types.Nonce, err error) { + nonce, err = s.fastForwardNonceIfNecessary(ctx, addr, localNonce) + return nonce, errors.Wrap(err, "NonceSyncer#fastForwardNoncesIfNecessary failed") } -func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address) error { +func (s nonceSyncerImpl) fastForwardNonceIfNecessary(ctx context.Context, address common.Address, localNonce types.Nonce) (types.Nonce, error) { chainNonce, err := s.pendingNonceFromEthClient(ctx, address) if err != nil { - return errors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") + return localNonce, errors.Wrap(err, "GetNextNonce failed to loadInitialNonceFromEthClient") } if chainNonce == 0 { - return nil + return localNonce, nil } - - keyNextNonce, err := s.kst.NextSequence(address, s.chainID, pg.WithParentCtx(ctx)) - if err != nil { - return err - } - - localNonce := keyNextNonce - hasInProgressTransaction, err := s.txStore.HasInProgressTransaction(address, s.chainID, pg.WithParentCtx(ctx)) - - if err != nil { - return errors.Wrapf(err, "failed to query for in_progress transaction for address %s", address.String()) - } else if hasInProgressTransaction { - // If we have an 'in_progress' transaction, our keys.next_nonce will be - // one lower than it should because we must have crashed mid-execution. - // The EthBroadcaster will automatically take care of this and - // increment it by one later, for now we just increment by one here. - localNonce++ - } - if chainNonce <= uint64(localNonce) { - return nil + if chainNonce <= localNonce { + return localNonce, nil } s.logger.Warnw(fmt.Sprintf("address %s has been used before, either by an external wallet or a different Chainlink node. "+ "Local nonce is %v but the on-chain nonce for this account was %v. "+ "It's possible that this node was restored from a backup. If so, transactions sent by the previous node will NOT be re-org protected and in rare cases may need to be manually bumped/resubmitted. "+ "Please note that using the chainlink keys with an external wallet is NOT SUPPORTED and can lead to missed or stuck transactions. ", address, localNonce, chainNonce), - "address", address.String(), "keyNextNonce", keyNextNonce, "localNonce", localNonce, "chainNonce", chainNonce) - - // Need to remember to decrement the chain nonce by one to account for in_progress transaction - newNextNonce := int64(chainNonce) - if hasInProgressTransaction { - newNextNonce-- - } + "address", address.String(), "localNonce", localNonce, "chainNonce", chainNonce) - err = s.txStore.UpdateKeyNextSequence(evmtypes.Nonce(newNextNonce), keyNextNonce, address, s.chainID, pg.WithParentCtx(ctx)) - - if errors.Is(err, ErrKeyNotUpdated) { - return errors.Errorf("NonceSyncer#fastForwardNonceIfNecessary optimistic lock failure fastforwarding nonce %v to %v for key %s", localNonce, chainNonce, address.String()) - } else if err == nil { - s.logger.Infow("Fast-forwarded nonce", "address", address, "newNextNonce", newNextNonce, "oldNextNonce", keyNextNonce) - } - return err + return chainNonce, nil } -func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (uint64, error) { +func (s nonceSyncerImpl) pendingNonceFromEthClient(ctx context.Context, account common.Address) (types.Nonce, error) { nextNonce, err := s.client.PendingSequenceAt(ctx, account) - return uint64(nextNonce), errors.WithStack(err) + return nextNonce, errors.WithStack(err) } diff --git a/core/chains/evm/txmgr/nonce_syncer_test.go b/core/chains/evm/txmgr/nonce_syncer_test.go index 05a6d4c8c7b..13e5fd02e8c 100644 --- a/core/chains/evm/txmgr/nonce_syncer_test.go +++ b/core/chains/evm/txmgr/nonce_syncer_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -11,9 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -24,149 +23,92 @@ func Test_NonceSyncer_Sync(t *testing.T) { t.Run("returns error if PendingNonceAt fails", func(t *testing.T) { db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - txStore := cltest.NewTxStore(t, db, cfg.Database()) - - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return from == addr - })).Return(uint64(0), errors.New("something exploded")) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - err := ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address()) + ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), errors.New("something exploded")) + _, err := ns.Sync(testutils.Context(t), from, types.Nonce(0)) require.Error(t, err) assert.Contains(t, err.Error(), "something exploded") cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, from, 0) }) t.Run("does nothing if chain nonce reflects local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - txStore := cltest.NewTxStore(t, db, cfg.Database()) - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return from == addr - })).Return(uint64(0), nil) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ethClient.On("PendingNonceAt", mock.Anything, from).Return(uint64(0), nil) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) + nonce, err := ns.Sync(testutils.Context(t), from, 0) + require.Equal(t, nonce.Int64(), int64(0)) + require.NoError(t, err) cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, from, 0) }) t.Run("does nothing if chain nonce is behind local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTxStore(t, db, cfg.Database()) + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) + ks := cltest.NewKeyStore(t, db, cfg.Database()).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - k1, _ := cltest.MustInsertRandomKey(t, ethKeyStore, int64(32)) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - return k1.Address == addr - })).Return(uint64(31), nil) + _, fromAddress := cltest.RandomKey{Nonce: 32}.MustInsert(t, ks) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) + // Used to mock the chain nonce + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(5), nil) + nonce, err := ns.Sync(testutils.Context(t), fromAddress, types.Nonce(32)) + require.Equal(t, nonce.Int64(), int64(32)) + require.NoError(t, err) cltest.AssertCount(t, db, "evm.txes", 0) cltest.AssertCount(t, db, "evm.tx_attempts", 0) - - assertDatabaseNonce(t, db, k1.Address, 32) }) t.Run("fast forwards if chain nonce is ahead of local nonce", func(t *testing.T) { db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTxStore(t, db, cfg.Database()) - + cfg := configtest.NewTestGeneralConfig(t) + txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(0)) - _, key2 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(32)) + _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore) + _, key2 := cltest.RandomKey{Nonce: 32}.MustInsert(t, ethKeyStore) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // Nothing to do for key2 - return key2 == addr - })).Return(uint64(32), nil) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 5 which is ahead of local nonce 0 - return key1 == addr - })).Return(uint64(5), nil) + key1LocalNonce := types.Nonce(0) + key2LocalNonce := types.Nonce(32) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) + ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient) - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - for _, k := range sendingKeys { - require.NoError(t, ns.Sync(testutils.Context(t), k.Address.Address())) - } + // Used to mock the chain nonce + ethClient.On("PendingNonceAt", mock.Anything, key1).Return(uint64(5), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, key2).Return(uint64(32), nil).Once() - assertDatabaseNonce(t, db, key1, 5) - }) - - t.Run("counts 'in_progress' eth_tx as bumping the local next nonce by 1", func(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, nil) - txStore := cltest.NewTestTxStore(t, db, cfg.Database()) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, key1 := cltest.MustInsertRandomKey(t, ethKeyStore, int64(0)) + syncerNonce, err := ns.Sync(testutils.Context(t), key1, key1LocalNonce) + require.NoError(t, err) + require.Greater(t, syncerNonce, key1LocalNonce) - cltest.MustInsertInProgressEthTxWithAttempt(t, txStore, 1, key1) - - ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 1 which is ahead of keys.next_nonce (0) - // by 1, but does not need to change when taking into account the in_progress tx - return key1 == addr - })).Return(uint64(1), nil) - ns := txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) - - sendingKeys := cltest.MustSendingKeyStates(t, ethKeyStore, testutils.FixtureChainID) - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - assertDatabaseNonce(t, db, key1, 0) - - ethClient = evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, mock.MatchedBy(func(addr common.Address) bool { - // key1 has chain nonce of 2 which is ahead of keys.next_nonce (0) - // by 2, but only ahead by 1 if we count the in_progress tx as +1 - return key1 == addr - })).Return(uint64(2), nil) - ns = txmgr.NewNonceSyncer(txStore, logger.TestLogger(t), ethClient, ethKeyStore) - - require.NoError(t, ns.Sync(testutils.Context(t), sendingKeys[0].Address.Address())) - assertDatabaseNonce(t, db, key1, 1) + syncerNonce, err = ns.Sync(testutils.Context(t), key2, key2LocalNonce) + require.NoError(t, err) + require.Equal(t, syncerNonce, key2LocalNonce) }) } - -func assertDatabaseNonce(t *testing.T, db *sqlx.DB, address common.Address, nonce int64) { - t.Helper() - - var nextNonce int64 - err := db.Get(&nextNonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1`, address) - require.NoError(t, err) - assert.Equal(t, nonce, nextNonce) -} diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 11843222999..830ed1ac17f 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -47,7 +47,7 @@ func TestReaper_ReapTxes(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, from := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) var nonce int64 oneDayAgo := time.Now().Add(-24 * time.Hour) diff --git a/core/chains/evm/txmgr/strategies_test.go b/core/chains/evm/txmgr/strategies_test.go index 085f3248643..9c5a1be37f1 100644 --- a/core/chains/evm/txmgr/strategies_test.go +++ b/core/chains/evm/txmgr/strategies_test.go @@ -10,9 +10,8 @@ import ( txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) func Test_SendEveryStrategy(t *testing.T) { @@ -22,7 +21,7 @@ func Test_SendEveryStrategy(t *testing.T) { assert.Equal(t, uuid.NullUUID{}, s.Subject()) - n, err := s.PruneQueue(nil, nil) + n, err := s.PruneQueue(testutils.Context(t), nil) assert.NoError(t, err) assert.Equal(t, int64(0), n) } @@ -40,7 +39,6 @@ func Test_DropOldestStrategy_Subject(t *testing.T) { func Test_DropOldestStrategy_PruneQueue(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) subject := uuid.New() queueSize := uint32(2) @@ -49,8 +47,8 @@ func Test_DropOldestStrategy_PruneQueue(t *testing.T) { t.Run("calls PrineUnstartedTxQueue for the given subject and queueSize, ignoring fromAddress", func(t *testing.T) { strategy1 := txmgrcommon.NewDropOldestStrategy(subject, queueSize, queryTimeout) - mockTxStore.On("PruneUnstartedTxQueue", queueSize, subject, mock.Anything, mock.Anything).Once().Return(int64(2), nil) - n, err := strategy1.PruneQueue(mockTxStore, pg.WithQueryer(db)) + mockTxStore.On("PruneUnstartedTxQueue", mock.Anything, queueSize, subject, mock.Anything, mock.Anything).Once().Return(int64(2), nil) + n, err := strategy1.PruneQueue(testutils.Context(t), mockTxStore) require.NoError(t, err) assert.Equal(t, int64(2), n) }) diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index 969e789031c..4636b708489 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -259,10 +259,9 @@ func (v *VRFV1Checker) Check( "meta", tx.Meta, "reqID", reqID) return errors.New("request already fulfilled") - } else { - // Request not fulfilled - return nil } + // Request not fulfilled + return nil } // VRFV2Checker is an implementation of TransmitChecker that checks whether a VRF V2 fulfillment @@ -351,11 +350,11 @@ func (v *VRFV2Checker) Check( "meta", tx.Meta, "vrfRequestId", vrfRequestID) return errors.New("request already fulfilled") - } else { - l.Debugw("Request not yet fulfilled", - "ethTxID", tx.ID, - "meta", tx.Meta, - "vrfRequestId", vrfRequestID) - return nil } + l.Debugw("Request not yet fulfilled", + "ethTxID", tx.ID, + "meta", tx.Meta, + "vrfRequestId", vrfRequestID) + return nil + } diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index f8a80990d31..79868e6a641 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -164,7 +164,7 @@ func TestTransmitCheckers(t *testing.T) { mock.AnythingOfType("*hexutil.Bytes"), "eth_call", mock.MatchedBy(func(callarg map[string]interface{}) bool { return fmt.Sprintf("%s", callarg["value"]) == "0x282" // 642 - }), "latest").Return(errors.New("error!")).Once() + }), "latest").Return(errors.New("error")).Once() // Non-revert errors are logged but should not prevent transmission, and do not need // to be passed to the caller @@ -230,11 +230,10 @@ func TestTransmitCheckers(t *testing.T) { } else if reqID == r2 { // Request 2 errors return v1.Callbacks{}, errors.New("error getting commitment") - } else { - return v1.Callbacks{ - SeedAndBlockNum: [32]byte{1}, - }, nil } + return v1.Callbacks{ + SeedAndBlockNum: [32]byte{1}, + }, nil }, Client: client, } @@ -325,10 +324,9 @@ func TestTransmitCheckers(t *testing.T) { } else if requestID.String() == "2" { // Request 2 errors return [32]byte{}, errors.New("error getting commitment") - } else { - // All other requests are unfulfilled - return [32]byte{1}, nil } + // All other requests are unfulfilled + return [32]byte{1}, nil }, HeadByNumber: func(ctx context.Context, n *big.Int) (*evmtypes.Head, error) { return &evmtypes.Head{ diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 79fcf101d5f..de8c6ff4ef8 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "math/big" - "sync/atomic" "testing" "time" @@ -45,7 +44,7 @@ import ( func makeTestEvmTxm( t *testing.T, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keystore.Eth, eventBroadcaster pg.EventBroadcaster) (txmgr.TxManager, error) { lggr := logger.TestLogger(t) - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), ethClient, lggr, 100*time.Millisecond, 2, 3, 2, 1000) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr, pgtest.NewQConfig(true)), ethClient, lggr, 100*time.Millisecond, false, 2, 3, 2, 1000) // logic for building components (from evm/evm_txm.go) ------- lggr.Infow("Initializing EVM transaction manager", @@ -87,7 +86,7 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore, nil) require.NoError(t, err) - _, err = txm.SendNativeToken(big.NewInt(0), from, to, *value, 21000) + _, err = txm.SendNativeToken(testutils.Context(t), big.NewInt(0), from, to, *value, 21000) require.Error(t, err) require.EqualError(t, err, "cannot send native token to zero address") } @@ -100,7 +99,7 @@ func TestTxm_CreateTransaction(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() gasLimit := uint32(1000) payload := []byte{1, 2, 3} @@ -117,9 +116,9 @@ func TestTxm_CreateTransaction(t *testing.T) { subject := uuid.New() strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{UUID: subject, Valid: true}) - strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) + strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) evmConfig.maxQueued = uint64(1) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -155,7 +154,7 @@ func TestTxm_CreateTransaction(t *testing.T) { t.Run("with queue at capacity does not insert eth_tx", func(t *testing.T) { evmConfig.maxQueued = uint64(1) - _, err := txm.CreateTransaction(txmgr.TxRequest{ + _, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -170,7 +169,7 @@ func TestTxm_CreateTransaction(t *testing.T) { t.Run("doesn't insert eth_tx if a matching tx already exists for that pipeline_task_run_id", func(t *testing.T) { evmConfig.maxQueued = uint64(3) id := uuid.New() - tx1, err := txm.CreateTransaction(txmgr.TxRequest{ + tx1, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -180,7 +179,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) assert.NoError(t, err) - tx2, err := txm.CreateTransaction(txmgr.TxRequest{ + tx2, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -195,7 +194,7 @@ func TestTxm_CreateTransaction(t *testing.T) { t.Run("returns error if eth key state is missing or doesn't match chain ID", func(t *testing.T) { rndAddr := testutils.NewAddress() - _, err := txm.CreateTransaction(txmgr.TxRequest{ + _, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: rndAddr, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -207,7 +206,7 @@ func TestTxm_CreateTransaction(t *testing.T) { _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *utils.NewBigI(1337)) - _, err = txm.CreateTransaction(txmgr.TxRequest{ + _, err = txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: otherAddress, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -225,7 +224,7 @@ func TestTxm_CreateTransaction(t *testing.T) { CheckerType: txmgr.TransmitCheckerTypeSimulate, } evmConfig.maxQueued = uint64(1) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -268,7 +267,7 @@ func TestTxm_CreateTransaction(t *testing.T) { CheckerType: txmgr.TransmitCheckerTypeVRFV2, VRFCoordinatorAddress: testutils.NewAddressPtr(), } - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -304,7 +303,7 @@ func TestTxm_CreateTransaction(t *testing.T) { require.NoError(t, err) require.Equal(t, fwdr.Address, fwdrAddr) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -328,7 +327,7 @@ func TestTxm_CreateTransaction(t *testing.T) { evmConfig.maxQueued = uint64(3) id := uuid.New() idempotencyKey := "1" - _, err := txm.CreateTransaction(txmgr.TxRequest{ + _, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ IdempotencyKey: &idempotencyKey, FromAddress: fromAddress, ToAddress: testutils.NewAddress(), @@ -344,7 +343,7 @@ func TestTxm_CreateTransaction(t *testing.T) { evmConfig.maxQueued = uint64(3) id := uuid.New() idempotencyKey := "2" - tx1, err := txm.CreateTransaction(txmgr.TxRequest{ + tx1, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ IdempotencyKey: &idempotencyKey, FromAddress: fromAddress, ToAddress: testutils.NewAddress(), @@ -355,7 +354,7 @@ func TestTxm_CreateTransaction(t *testing.T) { }) assert.NoError(t, err) - tx2, err := txm.CreateTransaction(txmgr.TxRequest{ + tx2, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ IdempotencyKey: &idempotencyKey, FromAddress: fromAddress, ToAddress: testutils.NewAddress(), @@ -512,8 +511,8 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) etKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - thisKey, _ := cltest.MustInsertRandomKey(t, etKeyStore, 1) - otherKey, _ := cltest.MustInsertRandomKey(t, etKeyStore, 1) + thisKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) + otherKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) fromAddress := thisKey.Address evmFromAddress := fromAddress @@ -523,9 +522,8 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { config, dbConfig, evmConfig := makeConfigs(t) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - kst := cltest.NewKeyStore(t, db, dbConfig) estimator := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator()) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth(), nil) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore, nil) require.NoError(t, err) t.Run("if another key has any transactions with insufficient eth errors, transmits as normal", func(t *testing.T) { @@ -535,16 +533,16 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) - strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) + strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: evmFromAddress, ToAddress: toAddress, EncodedPayload: payload, FeeLimit: gasLimit, Meta: nil, Strategy: strategy, - }, pg.WithParentCtx(context.Background())) + }) assert.NoError(t, err) require.Equal(t, payload, etx.EncodedPayload) @@ -559,9 +557,9 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { cltest.MustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, thisKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) - strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) + strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: evmFromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -580,10 +578,10 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 42, thisKey.Address) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) - strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) + strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(int64(0), nil) evmConfig.maxQueued = uint64(1) - etx, err := txm.CreateTransaction(txmgr.TxRequest{ + etx, err := txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: evmFromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -648,23 +646,6 @@ func TestTxm_Lifecycle(t *testing.T) { unsub.AwaitOrFail(t, 1*time.Second) } -type fnMock struct{ called atomic.Bool } - -func (fm *fnMock) Fn() { - swapped := fm.called.CompareAndSwap(false, true) - if !swapped { - panic("func called more than once") - } -} - -func (fm *fnMock) AssertNotCalled(t *testing.T) { - assert.False(t, fm.called.Load()) -} - -func (fm *fnMock) AssertCalled(t *testing.T) { - assert.True(t, fm.called.Load()) -} - func TestTxm_Reset(t *testing.T) { t.Parallel() @@ -674,8 +655,8 @@ func TestTxm_Reset(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) kst := cltest.NewKeyStore(t, db, cfg.Database()) - _, addr := cltest.MustInsertRandomKey(t, kst.Eth(), 5) - _, addr2 := cltest.MustInsertRandomKey(t, kst.Eth(), 3) + _, addr := cltest.RandomKey{Nonce: 5}.MustInsert(t, kst.Eth()) + _, addr2 := cltest.RandomKey{Nonce: 3}.MustInsert(t, kst.Eth()) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) // 4 confirmed tx from addr1 for i := int64(0); i < 4; i++ { @@ -687,8 +668,6 @@ func TestTxm_Reset(t *testing.T) { } ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - ethClient.On("PendingNonceAt", mock.Anything, addr).Return(uint64(0), nil) - ethClient.On("PendingNonceAt", mock.Anything, addr2).Return(uint64(0), nil) ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(nil, nil) ethClient.On("BatchCallContextAll", mock.Anything, mock.Anything).Return(nil).Maybe() eventBroadcaster := pgmocks.NewEventBroadcaster(t) @@ -707,35 +686,23 @@ func TestTxm_Reset(t *testing.T) { } t.Run("returns error if not started", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, false) + err := txm.Reset(addr, false) require.Error(t, err) assert.EqualError(t, err, "not started") - - f.AssertNotCalled(t) }) require.NoError(t, txm.Start(testutils.Context(t))) defer func() { assert.NoError(t, txm.Close()) }() - t.Run("calls function if started", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, false) + t.Run("returns no error if started", func(t *testing.T) { + err := txm.Reset(addr, false) require.NoError(t, err) - - f.AssertCalled(t) }) - t.Run("calls function and deletes relevant evm.txes if abandon=true", func(t *testing.T) { - f := new(fnMock) - - err := txm.Reset(f.Fn, addr, true) + t.Run("deletes relevant evm.txes if abandon=true", func(t *testing.T) { + err := txm.Reset(addr, true) require.NoError(t, err) - f.AssertCalled(t) - var s string err = db.Get(&s, `SELECT error FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) require.NoError(t, err) diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index a4625f6f1c0..683a49692b6 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -94,7 +94,7 @@ func TestEthTxAttempt_GetSignedTx(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) tx := gethTypes.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) chainID := big.NewInt(3) diff --git a/core/chains/evm/types/nonce.go b/core/chains/evm/types/nonce.go index 0c3256dc545..e9caf98c763 100644 --- a/core/chains/evm/types/nonce.go +++ b/core/chains/evm/types/nonce.go @@ -17,3 +17,7 @@ func (n Nonce) Int64() int64 { func (n Nonce) String() string { return strconv.FormatInt(n.Int64(), 10) } + +func GenerateNextNonce(prev Nonce) Nonce { + return Nonce(prev + 1) +} diff --git a/core/chains/internal/utils.go b/core/chains/internal/utils.go deleted file mode 100644 index 0932f12209c..00000000000 --- a/core/chains/internal/utils.go +++ /dev/null @@ -1,109 +0,0 @@ -package internal - -import ( - "encoding/base64" - "errors" - "fmt" - "net/url" - "strconv" - - "github.com/smartcontractkit/chainlink-relay/pkg/types" -) - -// PageToken is simple internal representation for coordination requests and responses in a paginated API -// It is inspired by the Google API Design patterns -// https://cloud.google.com/apis/design/design_patterns#list_pagination -// https://google.aip.dev/158 -type PageToken struct { - Page int - Size int -} - -var ( - ErrInvalidToken = errors.New("invalid page token") - ErrOutOfRange = errors.New("out of range") - defaultSize = 100 -) - -// Encode the token in base64 for transmission for the wire -func (pr *PageToken) Encode() string { - if pr.Size == 0 { - pr.Size = defaultSize - } - // this is a simple minded implementation and may benefit from something fancier - // note that this is a valid url.Query string, which we leverage in decoding - s := fmt.Sprintf("page=%d&size=%d", pr.Page, pr.Size) - return base64.RawStdEncoding.EncodeToString([]byte(s)) -} - -// b64enc must be the base64 encoded token string, corresponding to [PageToken.Encode()] -func NewPageToken(b64enc string) (*PageToken, error) { - // empty is valid - if b64enc == "" { - return &PageToken{Page: 0, Size: defaultSize}, nil - } - - b, err := base64.RawStdEncoding.DecodeString(b64enc) - if err != nil { - return nil, err - } - // here too, this is simple minded and could be fancier - - vals, err := url.ParseQuery(string(b)) - if err != nil { - return nil, err - } - if !(vals.Has("page") && vals.Has("size")) { - return nil, ErrInvalidToken - } - page, err := strconv.Atoi(vals.Get("page")) - if err != nil { - return nil, fmt.Errorf("%w: bad page", ErrInvalidToken) - } - size, err := strconv.Atoi(vals.Get("size")) - if err != nil { - return nil, fmt.Errorf("%w: bad size", ErrInvalidToken) - } - return &PageToken{ - Page: page, - Size: size, - }, err -} - -func ValidatePageToken(pageSize int, token string) (page int, err error) { - - if token == "" { - return 0, nil - } - t, err := NewPageToken(token) - if err != nil { - return -1, err - } - return t.Page, nil -} - -// if start is out of range, must return ErrOutOfRange -type ListNodeStatusFn = func(start, end int) (stats []types.NodeStatus, total int, err error) - -func ListNodeStatuses(pageSize int, pageToken string, listFn ListNodeStatusFn) (stats []types.NodeStatus, nextPageToken string, total int, err error) { - if pageSize == 0 { - pageSize = defaultSize - } - t := &PageToken{Page: 0, Size: pageSize} - if pageToken != "" { - t, err = NewPageToken(pageToken) - if err != nil { - return nil, "", -1, err - } - } - start, end := t.Page*t.Size, (t.Page+1)*t.Size - stats, total, err = listFn(start, end) - if err != nil { - return stats, "", -1, err - } - if total > end { - next_token := &PageToken{Page: t.Page + 1, Size: t.Size} - nextPageToken = next_token.Encode() - } - return stats, nextPageToken, total, nil -} diff --git a/core/chains/internal/utils_test.go b/core/chains/internal/utils_test.go deleted file mode 100644 index 5a47ed3d8ff..00000000000 --- a/core/chains/internal/utils_test.go +++ /dev/null @@ -1,166 +0,0 @@ -package internal - -import ( - "encoding/base64" - "fmt" - "reflect" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink-relay/pkg/types" -) - -func TestNewPageToken(t *testing.T) { - type args struct { - t *PageToken - } - tests := []struct { - name string - args args - want *PageToken - wantErr bool - }{ - { - name: "empty", - args: args{t: &PageToken{}}, - want: &PageToken{Page: 0, Size: defaultSize}, - }, - { - name: "page set, size unset", - args: args{t: &PageToken{Page: 1}}, - want: &PageToken{Page: 1, Size: defaultSize}, - }, - { - name: "page set, size set", - args: args{t: &PageToken{Page: 3, Size: 10}}, - want: &PageToken{Page: 3, Size: 10}, - }, - { - name: "page unset, size set", - args: args{t: &PageToken{Size: 17}}, - want: &PageToken{Page: 0, Size: 17}, - }, - } - for _, tt := range tests { - enc := tt.args.t.Encode() - t.Run(tt.name, func(t *testing.T) { - got, err := NewPageToken(enc) - if (err != nil) != tt.wantErr { - t.Errorf("NewPageToken() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("NewPageToken() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestListNodeStatuses(t *testing.T) { - testStats := []types.NodeStatus{ - types.NodeStatus{ - ChainID: "chain-1", - Name: "name-1", - }, - types.NodeStatus{ - ChainID: "chain-2", - Name: "name-2", - }, - types.NodeStatus{ - ChainID: "chain-3", - Name: "name-3", - }, - } - - type args struct { - pageSize int - pageToken string - listFn ListNodeStatusFn - } - tests := []struct { - name string - args args - wantStats []types.NodeStatus - wantNext_pageToken string - wantTotal int - wantErr bool - }{ - { - name: "all on first page", - args: args{ - pageSize: 10, // > length of test stats - pageToken: "", - listFn: func(start, end int) ([]types.NodeStatus, int, error) { - return testStats, len(testStats), nil - }, - }, - wantNext_pageToken: "", - wantTotal: len(testStats), - wantStats: testStats, - }, - { - name: "small first page", - args: args{ - pageSize: len(testStats) - 1, - pageToken: "", - listFn: func(start, end int) ([]types.NodeStatus, int, error) { - return testStats[start:end], len(testStats), nil - }, - }, - wantNext_pageToken: base64.RawStdEncoding.EncodeToString([]byte("page=1&size=2")), // hard coded 2 is len(testStats)-1 - wantTotal: len(testStats), - wantStats: testStats[0 : len(testStats)-1], - }, - { - name: "second page", - args: args{ - pageSize: len(testStats) - 1, - pageToken: base64.RawStdEncoding.EncodeToString([]byte("page=1&size=2")), // hard coded 2 is len(testStats)-1 - listFn: func(start, end int) ([]types.NodeStatus, int, error) { - // note list function must do the start, end bound checking. here we are making it simple - if end > len(testStats) { - end = len(testStats) - } - return testStats[start:end], len(testStats), nil - }, - }, - wantNext_pageToken: "", - wantTotal: len(testStats), - wantStats: testStats[len(testStats)-1:], - }, - { - name: "bad list fn", - args: args{ - listFn: func(start, end int) ([]types.NodeStatus, int, error) { - return nil, 0, fmt.Errorf("i'm a bad list fn") - }, - }, - wantTotal: -1, - wantErr: true, - }, - { - name: "invalid token", - args: args{ - pageToken: "invalid token", - listFn: func(start, end int) ([]types.NodeStatus, int, error) { - return testStats[start:end], len(testStats), nil - }, - }, - wantTotal: -1, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotStats, gotNext_pageToken, gotTotal, err := ListNodeStatuses(tt.args.pageSize, tt.args.pageToken, tt.args.listFn) - if (err != nil) != tt.wantErr { - t.Errorf("ListNodeStatuses() error = %v, wantErr %v", err, tt.wantErr) - return - } - assert.Equal(t, tt.wantStats, gotStats) - assert.Equal(t, tt.wantNext_pageToken, gotNext_pageToken) - assert.Equal(t, tt.wantTotal, gotTotal) - }) - } -} diff --git a/core/chains/solana/chain.go b/core/chains/solana/chain.go deleted file mode 100644 index 682fb23f9f2..00000000000 --- a/core/chains/solana/chain.go +++ /dev/null @@ -1,461 +0,0 @@ -package solana - -import ( - "context" - "fmt" - "math/big" - "math/rand" - "strings" - "sync" - "time" - - solanago "github.com/gagliardetto/solana-go" - "github.com/gagliardetto/solana-go/programs/system" - "github.com/gagliardetto/solana-go/rpc" - "github.com/pkg/errors" - "go.uber.org/multierr" - "golang.org/x/exp/maps" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/internal" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana/monitor" - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -// DefaultRequestTimeout is the default Solana client timeout. -const DefaultRequestTimeout = 30 * time.Second - -// ChainOpts holds options for configuring a Chain. -type ChainOpts struct { - Logger logger.Logger - KeyStore loop.Keystore -} - -func (o *ChainOpts) Validate() (err error) { - required := func(s string) error { - return errors.Errorf("%s is required", s) - } - if o.Logger == nil { - err = multierr.Append(err, required("Logger")) - } - if o.KeyStore == nil { - err = multierr.Append(err, required("KeyStore")) - } - return -} - -func (o *ChainOpts) GetLogger() logger.Logger { - return o.Logger -} - -func NewChain(cfg *SolanaConfig, opts ChainOpts) (solana.Chain, error) { - if !cfg.IsEnabled() { - return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) - } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) - if err != nil { - return nil, err - } - return c, nil -} - -var _ solana.Chain = (*chain)(nil) - -type chain struct { - utils.StartStopOnce - id string - cfg *SolanaConfig - txm *txm.Txm - balanceMonitor services.ServiceCtx - lggr logger.Logger - - // tracking node chain id for verification - clientCache map[string]*verifiedCachedClient // map URL -> {client, chainId} [mainnet/testnet/devnet/localnet] - clientLock sync.RWMutex -} - -type verifiedCachedClient struct { - chainID string - expectedChainID string - nodeURL string - - chainIDVerified bool - chainIDVerifiedLock sync.RWMutex - - client.ReaderWriter -} - -func (v *verifiedCachedClient) verifyChainID() (bool, error) { - v.chainIDVerifiedLock.RLock() - if v.chainIDVerified { - v.chainIDVerifiedLock.RUnlock() - return true, nil - } - v.chainIDVerifiedLock.RUnlock() - - var err error - - v.chainIDVerifiedLock.Lock() - defer v.chainIDVerifiedLock.Unlock() - - v.chainID, err = v.ReaderWriter.ChainID() - if err != nil { - v.chainIDVerified = false - return v.chainIDVerified, errors.Wrap(err, "failed to fetch ChainID in verifiedCachedClient") - } - - // check chainID matches expected chainID - expectedChainID := strings.ToLower(v.expectedChainID) - if v.chainID != expectedChainID { - v.chainIDVerified = false - return v.chainIDVerified, errors.Errorf("client returned mismatched chain id (expected: %s, got: %s): %s", expectedChainID, v.chainID, v.nodeURL) - } - - v.chainIDVerified = true - - return v.chainIDVerified, nil -} - -func (v *verifiedCachedClient) SendTx(ctx context.Context, tx *solanago.Transaction) (solanago.Signature, error) { - verified, err := v.verifyChainID() - if !verified { - return [64]byte{}, err - } - - return v.ReaderWriter.SendTx(ctx, tx) -} - -func (v *verifiedCachedClient) SimulateTx(ctx context.Context, tx *solanago.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { - verified, err := v.verifyChainID() - if !verified { - return nil, err - } - - return v.ReaderWriter.SimulateTx(ctx, tx, opts) -} - -func (v *verifiedCachedClient) SignatureStatuses(ctx context.Context, sigs []solanago.Signature) ([]*rpc.SignatureStatusesResult, error) { - verified, err := v.verifyChainID() - if !verified { - return nil, err - } - - return v.ReaderWriter.SignatureStatuses(ctx, sigs) -} - -func (v *verifiedCachedClient) Balance(addr solanago.PublicKey) (uint64, error) { - verified, err := v.verifyChainID() - if !verified { - return 0, err - } - - return v.ReaderWriter.Balance(addr) -} - -func (v *verifiedCachedClient) SlotHeight() (uint64, error) { - verified, err := v.verifyChainID() - if !verified { - return 0, err - } - - return v.ReaderWriter.SlotHeight() -} - -func (v *verifiedCachedClient) LatestBlockhash() (*rpc.GetLatestBlockhashResult, error) { - verified, err := v.verifyChainID() - if !verified { - return nil, err - } - - return v.ReaderWriter.LatestBlockhash() -} - -func (v *verifiedCachedClient) ChainID() (string, error) { - verified, err := v.verifyChainID() - if !verified { - return "", err - } - - return v.chainID, nil -} - -func (v *verifiedCachedClient) GetFeeForMessage(msg string) (uint64, error) { - verified, err := v.verifyChainID() - if !verified { - return 0, err - } - - return v.ReaderWriter.GetFeeForMessage(msg) -} - -func (v *verifiedCachedClient) GetAccountInfoWithOpts(ctx context.Context, addr solanago.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { - verified, err := v.verifyChainID() - if !verified { - return nil, err - } - - return v.ReaderWriter.GetAccountInfoWithOpts(ctx, addr, opts) -} - -func newChain(id string, cfg *SolanaConfig, ks loop.Keystore, lggr logger.Logger) (*chain, error) { - lggr = logger.With(lggr, "chainID", id, "chain", "solana") - var ch = chain{ - id: id, - cfg: cfg, - lggr: logger.Named(lggr, "Chain"), - clientCache: map[string]*verifiedCachedClient{}, - } - tc := func() (client.ReaderWriter, error) { - return ch.getClient() - } - ch.txm = txm.NewTxm(ch.id, tc, cfg, ks, lggr) - ch.balanceMonitor = monitor.NewBalanceMonitor(ch.id, cfg, lggr, ks, ch.Reader) - return &ch, nil -} - -// ChainService interface -func (c *chain) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - toml, err := c.cfg.TOMLString() - if err != nil { - return relaytypes.ChainStatus{}, err - } - return relaytypes.ChainStatus{ - ID: c.id, - Enabled: c.cfg.IsEnabled(), - Config: toml, - }, nil -} - -func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return internal.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) -} - -func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return c.sendTx(ctx, from, to, amount, balanceCheck) -} - -func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { - stats := make([]relaytypes.NodeStatus, 0) - total := len(c.cfg.Nodes) - if start >= total { - return stats, total, internal.ErrOutOfRange - } - if end > total { - end = total - } - nodes := c.cfg.Nodes[start:end] - for _, node := range nodes { - stat, err := nodeStatus(node, c.ChainID()) - if err != nil { - return stats, total, err - } - stats = append(stats, stat) - } - return stats, total, nil -} - -func (c *chain) Name() string { - return c.lggr.Name() -} - -func (c *chain) ID() string { - return c.id -} - -func (c *chain) Config() config.Config { - return c.cfg -} - -func (c *chain) TxManager() solana.TxManager { - return c.txm -} - -func (c *chain) Reader() (client.Reader, error) { - return c.getClient() -} - -func (c *chain) ChainID() relay.ChainID { - return relay.ChainID(c.id) -} - -// getClient returns a client, randomly selecting one from available and valid nodes -func (c *chain) getClient() (client.ReaderWriter, error) { - var node db.Node - var client client.ReaderWriter - nodes, err := c.cfg.ListNodes() - if err != nil { - return nil, errors.Wrap(err, "failed to get nodes") - } - if len(nodes) == 0 { - return nil, errors.New("no nodes available") - } - // #nosec - index := rand.Perm(len(nodes)) // list of node indexes to try - for _, i := range index { - node = nodes[i] - // create client and check - client, err = c.verifiedClient(node) - // if error, try another node - if err != nil { - c.lggr.Warnw("failed to create node", "name", node.Name, "solana-url", node.SolanaURL, "err", err.Error()) - continue - } - // if all checks passed, mark found and break loop - break - } - // if no valid node found, exit with error - if client == nil { - return nil, errors.New("no node valid nodes available") - } - c.lggr.Debugw("Created client", "name", node.Name, "solana-url", node.SolanaURL) - return client, nil -} - -// verifiedClient returns a client for node or an error if fails to create the client. -// The client will still be returned if the nodes are not valid, or the chain id doesn't match. -// Further client calls will try and verify the client, and fail if the client is still not valid. -func (c *chain) verifiedClient(node db.Node) (client.ReaderWriter, error) { - url := node.SolanaURL - var err error - - // check if cached client exists - c.clientLock.RLock() - cl, exists := c.clientCache[url] - c.clientLock.RUnlock() - - if !exists { - cl = &verifiedCachedClient{ - nodeURL: url, - expectedChainID: c.id, - } - // create client - cl.ReaderWriter, err = client.NewClient(url, c.cfg, DefaultRequestTimeout, logger.Named(c.lggr, "Client."+node.Name)) - if err != nil { - return nil, errors.Wrap(err, "failed to create client") - } - - c.clientLock.Lock() - // recheck when writing to prevent parallel writes (discard duplicate if exists) - if cached, exists := c.clientCache[url]; !exists { - c.clientCache[url] = cl - } else { - cl = cached - } - c.clientLock.Unlock() - } - - return cl, nil -} - -func (c *chain) Start(ctx context.Context) error { - return c.StartOnce("Chain", func() error { - c.lggr.Debug("Starting") - c.lggr.Debug("Starting txm") - c.lggr.Debug("Starting balance monitor") - var ms services.MultiStart - return ms.Start(ctx, c.txm, c.balanceMonitor) - }) -} - -func (c *chain) Close() error { - return c.StopOnce("Chain", func() error { - c.lggr.Debug("Stopping") - c.lggr.Debug("Stopping txm") - c.lggr.Debug("Stopping balance monitor") - return services.CloseAll(c.txm, c.balanceMonitor) - }) -} - -func (c *chain) Ready() error { - return multierr.Combine( - c.StartStopOnce.Ready(), - c.txm.Ready(), - ) -} - -func (c *chain) HealthReport() map[string]error { - report := map[string]error{c.Name(): c.StartStopOnce.Healthy()} - maps.Copy(report, c.txm.HealthReport()) - return report -} - -func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - reader, err := c.Reader() - if err != nil { - return fmt.Errorf("chain unreachable: %w", err) - } - - fromKey, err := solanago.PublicKeyFromBase58(from) - if err != nil { - return fmt.Errorf("failed to parse from key: %w", err) - } - toKey, err := solanago.PublicKeyFromBase58(to) - if err != nil { - return fmt.Errorf("failed to parse to key: %w", err) - } - if !amount.IsUint64() { - return fmt.Errorf("amount %s overflows uint64", amount) - } - amountI := amount.Uint64() - - blockhash, err := reader.LatestBlockhash() - if err != nil { - return fmt.Errorf("failed to get latest block hash: %w", err) - } - tx, err := solanago.NewTransaction( - []solanago.Instruction{ - system.NewTransferInstruction( - amountI, - fromKey, - toKey, - ).Build(), - }, - blockhash.Value.Blockhash, - solanago.TransactionPayer(fromKey), - ) - if err != nil { - return fmt.Errorf("failed to create tx: %w", err) - } - - if balanceCheck { - if err = solanaValidateBalance(reader, fromKey, amountI, tx.Message.ToBase64()); err != nil { - return fmt.Errorf("failed to validate balance: %w", err) - } - } - - txm := c.TxManager() - err = txm.Enqueue("", tx) - if err != nil { - return fmt.Errorf("transaction failed: %w", err) - } - return nil -} - -func solanaValidateBalance(reader client.Reader, from solanago.PublicKey, amount uint64, msg string) error { - balance, err := reader.Balance(from) - if err != nil { - return err - } - - fee, err := reader.GetFeeForMessage(msg) - if err != nil { - return err - } - - if balance < (amount + fee) { - return fmt.Errorf("balance %d is too low for this transaction to be executed: amount %d + fee %d", balance, amount, fee) - } - return nil -} diff --git a/core/chains/solana/chain_test.go b/core/chains/solana/chain_test.go deleted file mode 100644 index c8dfcf8501e..00000000000 --- a/core/chains/solana/chain_test.go +++ /dev/null @@ -1,231 +0,0 @@ -package solana - -import ( - "fmt" - "io" - "net/http" - "net/http/httptest" - "strings" - "sync" - "testing" - - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-relay/pkg/utils" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" - solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" - - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -const TestSolanaGenesisHashTemplate = `{"jsonrpc":"2.0","result":"%s","id":1}` - -func TestSolanaChain_GetClient(t *testing.T) { - checkOnce := map[string]struct{}{} - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - out := fmt.Sprintf(TestSolanaGenesisHashTemplate, client.MainnetGenesisHash) // mainnet genesis hash - - if !strings.Contains(r.URL.Path, "/mismatch") { - // devnet gensis hash - out = fmt.Sprintf(TestSolanaGenesisHashTemplate, client.DevnetGenesisHash) - - // clients with correct chainID should request chainID only once - if _, exists := checkOnce[r.URL.Path]; exists { - assert.NoError(t, errors.Errorf("rpc has been called once already for successful client '%s'", r.URL.Path)) - } - checkOnce[r.URL.Path] = struct{}{} - } - - _, err := w.Write([]byte(out)) - require.NoError(t, err) - })) - defer mockServer.Close() - - ch := solcfg.Chain{} - ch.SetDefaults() - cfg := &SolanaConfig{ - ChainID: ptr("devnet"), - Chain: ch, - } - testChain := chain{ - id: "devnet", - cfg: cfg, - lggr: logger.TestLogger(t), - clientCache: map[string]*verifiedCachedClient{}, - } - - cfg.Nodes = SolanaNodes([]*solcfg.Node{ - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/1"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/2"), - }, - }) - _, err := testChain.getClient() - assert.NoError(t, err) - - // random nodes (happy path, 1 valid + multiple invalid) - cfg.Nodes = SolanaNodes([]*solcfg.Node{ - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/1"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/3"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/4"), - }, - }) - _, err = testChain.getClient() - assert.NoError(t, err) - - // empty nodes response - cfg.Nodes = nil - _, err = testChain.getClient() - assert.Error(t, err) - - // no valid nodes to select from - cfg.Nodes = SolanaNodes([]*solcfg.Node{ - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/1"), - }, - &solcfg.Node{ - Name: ptr("devnet"), - URL: utils.MustParseURL(mockServer.URL + "/mismatch/2"), - }, - }) - _, err = testChain.getClient() - assert.NoError(t, err) -} - -func TestSolanaChain_VerifiedClient(t *testing.T) { - called := false - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - out := `{ "jsonrpc": "2.0", "result": 1234, "id": 1 }` // getSlot response - - body, err := io.ReadAll(r.Body) - require.NoError(t, err) - - // handle getGenesisHash request - if strings.Contains(string(body), "getGenesisHash") { - // should only be called once, chainID will be cached in chain - // allowing `mismatch` to be ignored, since invalid nodes will try to verify the chain ID - // if it is not verified - if !strings.Contains(r.URL.Path, "/mismatch") && called { - assert.NoError(t, errors.New("rpc has been called once already")) - } - // devnet genesis hash - out = fmt.Sprintf(TestSolanaGenesisHashTemplate, client.DevnetGenesisHash) - } - _, err = w.Write([]byte(out)) - require.NoError(t, err) - called = true - })) - defer mockServer.Close() - - ch := solcfg.Chain{} - ch.SetDefaults() - cfg := &SolanaConfig{ - ChainID: ptr("devnet"), - Chain: ch, - } - testChain := chain{ - cfg: cfg, - lggr: logger.TestLogger(t), - clientCache: map[string]*verifiedCachedClient{}, - } - node := db.Node{SolanaURL: mockServer.URL} - - // happy path - testChain.id = "devnet" - _, err := testChain.verifiedClient(node) - assert.NoError(t, err) - - // retrieve cached client and retrieve slot height - c, err := testChain.verifiedClient(node) - assert.NoError(t, err) - slot, err := c.SlotHeight() - assert.NoError(t, err) - assert.Equal(t, uint64(1234), slot) - - node.SolanaURL = mockServer.URL + "/mismatch" - testChain.id = "incorrect" - c, err = testChain.verifiedClient(node) - assert.NoError(t, err) - _, err = c.ChainID() - // expect error from id mismatch (even if using a cached client) when performing RPC calls - assert.Error(t, err) - assert.Equal(t, fmt.Sprintf("client returned mismatched chain id (expected: %s, got: %s): %s", "incorrect", "devnet", node.SolanaURL), err.Error()) -} - -func TestSolanaChain_VerifiedClient_ParallelClients(t *testing.T) { - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - out := fmt.Sprintf(TestSolanaGenesisHashTemplate, client.DevnetGenesisHash) - _, err := w.Write([]byte(out)) - require.NoError(t, err) - })) - defer mockServer.Close() - - ch := solcfg.Chain{} - ch.SetDefaults() - cfg := &SolanaConfig{ - ChainID: ptr("devnet"), - Enabled: ptr(true), - Chain: ch, - } - testChain := chain{ - id: "devnet", - cfg: cfg, - lggr: logger.TestLogger(t), - clientCache: map[string]*verifiedCachedClient{}, - } - node := db.Node{SolanaURL: mockServer.URL} - - var wg sync.WaitGroup - wg.Add(2) - - var client0 client.ReaderWriter - var client1 client.ReaderWriter - var err0 error - var err1 error - - // call verifiedClient in parallel - go func() { - client0, err0 = testChain.verifiedClient(node) - assert.NoError(t, err0) - wg.Done() - }() - go func() { - client1, err1 = testChain.verifiedClient(node) - assert.NoError(t, err1) - wg.Done() - }() - - wg.Wait() - - // check if pointers are all the same - assert.Equal(t, testChain.clientCache[mockServer.URL], client0) - assert.Equal(t, testChain.clientCache[mockServer.URL], client1) -} - -func ptr[T any](t T) *T { - return &t -} diff --git a/core/chains/solana/config.go b/core/chains/solana/config.go deleted file mode 100644 index b6e4a077f9e..00000000000 --- a/core/chains/solana/config.go +++ /dev/null @@ -1,272 +0,0 @@ -package solana - -import ( - "fmt" - "net/url" - "time" - - "github.com/gagliardetto/solana-go/rpc" - "github.com/pelletier/go-toml/v2" - "go.uber.org/multierr" - "golang.org/x/exp/slices" - - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - soldb "github.com/smartcontractkit/chainlink-solana/pkg/solana/db" - - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" -) - -type SolanaConfigs []*SolanaConfig - -func (cs SolanaConfigs) ValidateConfig() (err error) { - return cs.validateKeys() -} - -func (cs SolanaConfigs) validateKeys() (err error) { - // Unique chain IDs - chainIDs := config.UniqueStrings{} - for i, c := range cs { - if chainIDs.IsDupe(c.ChainID) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), *c.ChainID)) - } - } - - // Unique node names - names := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - if names.IsDupe(n.Name) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), *n.Name)) - } - } - } - - // Unique URLs - urls := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - u := (*url.URL)(n.URL) - if urls.IsDupeFmt(u) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.URL", i, j), u.String())) - } - } - } - return -} - -func (cs *SolanaConfigs) SetFrom(fs *SolanaConfigs) (err error) { - if err1 := fs.validateKeys(); err1 != nil { - return err1 - } - for _, f := range *fs { - if f.ChainID == nil { - *cs = append(*cs, f) - } else if i := slices.IndexFunc(*cs, func(c *SolanaConfig) bool { - return c.ChainID != nil && *c.ChainID == *f.ChainID - }); i == -1 { - *cs = append(*cs, f) - } else { - (*cs)[i].SetFrom(f) - } - } - return -} - -func nodeStatus(n *solcfg.Node, id relay.ChainID) (relaytypes.NodeStatus, error) { - var s relaytypes.NodeStatus - s.ChainID = id - s.Name = *n.Name - b, err := toml.Marshal(n) - if err != nil { - return relaytypes.NodeStatus{}, err - } - s.Config = string(b) - return s, nil -} - -type SolanaNodes []*solcfg.Node - -func (ns *SolanaNodes) SetFrom(fs *SolanaNodes) { - for _, f := range *fs { - if f.Name == nil { - *ns = append(*ns, f) - } else if i := slices.IndexFunc(*ns, func(n *solcfg.Node) bool { - return n.Name != nil && *n.Name == *f.Name - }); i == -1 { - *ns = append(*ns, f) - } else { - setFromNode((*ns)[i], f) - } - } -} - -func setFromNode(n, f *solcfg.Node) { - if f.Name != nil { - n.Name = f.Name - } - if f.URL != nil { - n.URL = f.URL - } -} - -func legacySolNode(n *solcfg.Node, id relay.ChainID) soldb.Node { - return soldb.Node{ - Name: *n.Name, - SolanaChainID: id, - SolanaURL: (*url.URL)(n.URL).String(), - } -} - -type SolanaConfig struct { - ChainID *string - // Do not access directly, use [IsEnabled] - Enabled *bool - solcfg.Chain - Nodes SolanaNodes -} - -func (c *SolanaConfig) IsEnabled() bool { - return c.Enabled == nil || *c.Enabled -} - -func (c *SolanaConfig) SetFrom(f *SolanaConfig) { - if f.ChainID != nil { - c.ChainID = f.ChainID - } - if f.Enabled != nil { - c.Enabled = f.Enabled - } - setFromChain(&c.Chain, &f.Chain) - c.Nodes.SetFrom(&f.Nodes) -} - -func setFromChain(c, f *solcfg.Chain) { - if f.BalancePollPeriod != nil { - c.BalancePollPeriod = f.BalancePollPeriod - } - if f.ConfirmPollPeriod != nil { - c.ConfirmPollPeriod = f.ConfirmPollPeriod - } - if f.OCR2CachePollPeriod != nil { - c.OCR2CachePollPeriod = f.OCR2CachePollPeriod - } - if f.OCR2CacheTTL != nil { - c.OCR2CacheTTL = f.OCR2CacheTTL - } - if f.TxTimeout != nil { - c.TxTimeout = f.TxTimeout - } - if f.TxRetryTimeout != nil { - c.TxRetryTimeout = f.TxRetryTimeout - } - if f.TxConfirmTimeout != nil { - c.TxConfirmTimeout = f.TxConfirmTimeout - } - if f.SkipPreflight != nil { - c.SkipPreflight = f.SkipPreflight - } - if f.Commitment != nil { - c.Commitment = f.Commitment - } - if f.MaxRetries != nil { - c.MaxRetries = f.MaxRetries - } -} - -func (c *SolanaConfig) ValidateConfig() (err error) { - if c.ChainID == nil { - err = multierr.Append(err, config.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) - } else if *c.ChainID == "" { - err = multierr.Append(err, config.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) - } - - if len(c.Nodes) == 0 { - err = multierr.Append(err, config.ErrMissing{Name: "Nodes", Msg: "must have at least one node"}) - } - return -} - -func (c *SolanaConfig) TOMLString() (string, error) { - b, err := toml.Marshal(c) - if err != nil { - return "", err - } - return string(b), nil -} - -var _ solcfg.Config = &SolanaConfig{} - -func (c *SolanaConfig) BalancePollPeriod() time.Duration { - return c.Chain.BalancePollPeriod.Duration() -} - -func (c *SolanaConfig) ConfirmPollPeriod() time.Duration { - return c.Chain.ConfirmPollPeriod.Duration() -} - -func (c *SolanaConfig) OCR2CachePollPeriod() time.Duration { - return c.Chain.OCR2CachePollPeriod.Duration() -} - -func (c *SolanaConfig) OCR2CacheTTL() time.Duration { - return c.Chain.OCR2CacheTTL.Duration() -} - -func (c *SolanaConfig) TxTimeout() time.Duration { - return c.Chain.TxTimeout.Duration() -} - -func (c *SolanaConfig) TxRetryTimeout() time.Duration { - return c.Chain.TxRetryTimeout.Duration() -} - -func (c *SolanaConfig) TxConfirmTimeout() time.Duration { - return c.Chain.TxConfirmTimeout.Duration() -} - -func (c *SolanaConfig) SkipPreflight() bool { - return *c.Chain.SkipPreflight -} - -func (c *SolanaConfig) Commitment() rpc.CommitmentType { - return rpc.CommitmentType(*c.Chain.Commitment) -} - -func (c *SolanaConfig) MaxRetries() *uint { - if c.Chain.MaxRetries == nil { - return nil - } - mr := uint(*c.Chain.MaxRetries) - return &mr -} - -func (c *SolanaConfig) FeeEstimatorMode() string { - return *c.Chain.FeeEstimatorMode -} - -func (c *SolanaConfig) ComputeUnitPriceMax() uint64 { - return *c.Chain.ComputeUnitPriceMax -} - -func (c *SolanaConfig) ComputeUnitPriceMin() uint64 { - return *c.Chain.ComputeUnitPriceMin -} - -func (c *SolanaConfig) ComputeUnitPriceDefault() uint64 { - return *c.Chain.ComputeUnitPriceDefault -} - -func (c *SolanaConfig) FeeBumpPeriod() time.Duration { - return c.Chain.FeeBumpPeriod.Duration() -} - -func (c *SolanaConfig) ListNodes() ([]soldb.Node, error) { - var allNodes []soldb.Node - for _, n := range c.Nodes { - allNodes = append(allNodes, legacySolNode(n, *c.ChainID)) - } - return allNodes, nil -} diff --git a/core/chains/solana/monitor/balance.go b/core/chains/solana/monitor/balance.go deleted file mode 100644 index 9734a9a3ca7..00000000000 --- a/core/chains/solana/monitor/balance.go +++ /dev/null @@ -1,150 +0,0 @@ -package monitor - -import ( - "context" - "time" - - "github.com/gagliardetto/solana-go" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - solanaClient "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" - - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -// Config defines the monitor configuration. -type Config interface { - BalancePollPeriod() time.Duration -} - -// Keystore provides the keys to be monitored. -type Keystore interface { - Accounts(ctx context.Context) ([]string, error) -} - -// NewBalanceMonitor returns a balance monitoring services.Service which reports the SOL balance of all ks keys to prometheus. -func NewBalanceMonitor(chainID string, cfg Config, lggr logger.Logger, ks Keystore, newReader func() (solanaClient.Reader, error)) services.ServiceCtx { - return newBalanceMonitor(chainID, cfg, lggr, ks, newReader) -} - -func newBalanceMonitor(chainID string, cfg Config, lggr logger.Logger, ks Keystore, newReader func() (solanaClient.Reader, error)) *balanceMonitor { - b := balanceMonitor{ - chainID: chainID, - cfg: cfg, - lggr: logger.Named(lggr, "BalanceMonitor"), - ks: ks, - newReader: newReader, - stop: make(chan struct{}), - done: make(chan struct{}), - } - b.updateFn = b.updateProm - return &b -} - -type balanceMonitor struct { - utils.StartStopOnce - chainID string - cfg Config - lggr logger.Logger - ks Keystore - newReader func() (solanaClient.Reader, error) - updateFn func(acc solana.PublicKey, lamports uint64) // overridable for testing - - reader solanaClient.Reader - - stop, done chan struct{} -} - -func (b *balanceMonitor) Name() string { - return b.lggr.Name() -} - -func (b *balanceMonitor) Start(context.Context) error { - return b.StartOnce("SolanaBalanceMonitor", func() error { - go b.monitor() - return nil - }) -} - -func (b *balanceMonitor) Close() error { - return b.StopOnce("SolanaBalanceMonitor", func() error { - close(b.stop) - <-b.done - return nil - }) -} - -func (b *balanceMonitor) HealthReport() map[string]error { - return map[string]error{b.Name(): b.Healthy()} -} - -func (b *balanceMonitor) monitor() { - defer close(b.done) - ctx, cancel := utils.ContextFromChan(b.stop) - defer cancel() - - tick := time.After(utils.WithJitter(b.cfg.BalancePollPeriod())) - for { - select { - case <-b.stop: - return - case <-tick: - b.updateBalances(ctx) - tick = time.After(utils.WithJitter(b.cfg.BalancePollPeriod())) - } - } -} - -// getReader returns the cached solanaClient.Reader, or creates a new one if nil. -func (b *balanceMonitor) getReader() (solanaClient.Reader, error) { - if b.reader == nil { - var err error - b.reader, err = b.newReader() - if err != nil { - return nil, err - } - } - return b.reader, nil -} - -func (b *balanceMonitor) updateBalances(ctx context.Context) { - keys, err := b.ks.Accounts(ctx) - if err != nil { - b.lggr.Errorw("Failed to get keys", "err", err) - return - } - if len(keys) == 0 { - return - } - reader, err := b.getReader() - if err != nil { - b.lggr.Errorw("Failed to get client", "err", err) - return - } - var gotSomeBals bool - for _, k := range keys { - // Check for shutdown signal, since Balance blocks and may be slow. - select { - case <-b.stop: - return - default: - } - pubKey, err := solana.PublicKeyFromBase58(k) - if err != nil { - b.lggr.Errorw("Failed parse public key", "account", k, "err", err) - continue - } - lamports, err := reader.Balance(pubKey) - if err != nil { - b.lggr.Errorw("Failed to get balance", "account", k, "err", err) - continue - } - gotSomeBals = true - b.updateFn(pubKey, lamports) - } - if !gotSomeBals { - // Try a new client next time. - b.reader = nil - } -} diff --git a/core/chains/solana/monitor/balance_test.go b/core/chains/solana/monitor/balance_test.go deleted file mode 100644 index 5f5ef8e807a..00000000000 --- a/core/chains/solana/monitor/balance_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package monitor - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/gagliardetto/solana-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" - - solanaRelay "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/mocks" -) - -func TestBalanceMonitor(t *testing.T) { - const chainID = "Chainlinktest-42" - ks := keystore{} - for i := 0; i < 3; i++ { - k, err := solkey.New() - assert.NoError(t, err) - ks = append(ks, k) - } - - bals := []uint64{0, 1, 1_000_000_000} - expBals := []string{ - "0.000000000", - "0.000000001", - "1.000000000", - } - - client := new(mocks.ReaderWriter) - client.Test(t) - type update struct{ acc, bal string } - var exp []update - for i := range bals { - acc := ks[i].PublicKey() - client.On("Balance", acc).Return(bals[i], nil) - exp = append(exp, update{acc.String(), expBals[i]}) - } - cfg := &config{balancePollPeriod: time.Second} - b := newBalanceMonitor(chainID, cfg, logger.TestLogger(t), ks, nil) - var got []update - done := make(chan struct{}) - b.updateFn = func(acc solana.PublicKey, lamports uint64) { - select { - case <-done: - return - default: - } - v := solanaRelay.LamportsToSol(lamports) // convert from lamports to SOL - got = append(got, update{acc.String(), fmt.Sprintf("%.9f", v)}) - if len(got) == len(exp) { - close(done) - } - } - b.reader = client - - require.NoError(t, b.Start(testutils.Context(t))) - t.Cleanup(func() { - assert.NoError(t, b.Close()) - client.AssertExpectations(t) - }) - select { - case <-time.After(testutils.WaitTimeout(t)): - t.Fatal("timed out waiting for balance monitor") - case <-done: - } - - assert.EqualValues(t, exp, got) -} - -type config struct { - balancePollPeriod time.Duration -} - -func (c *config) BalancePollPeriod() time.Duration { - return c.balancePollPeriod -} - -type keystore []solkey.Key - -func (k keystore) Accounts(ctx context.Context) (ks []string, err error) { - for _, acc := range k { - ks = append(ks, acc.PublicKeyStr()) - } - return -} diff --git a/core/chains/solana/monitor/prom.go b/core/chains/solana/monitor/prom.go deleted file mode 100644 index f853b6610e9..00000000000 --- a/core/chains/solana/monitor/prom.go +++ /dev/null @@ -1,19 +0,0 @@ -package monitor - -import ( - "github.com/gagliardetto/solana-go" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - solanaRelay "github.com/smartcontractkit/chainlink-solana/pkg/solana" -) - -var promSolanaBalance = promauto.NewGaugeVec( - prometheus.GaugeOpts{Name: "solana_balance", Help: "Solana account balances"}, - []string{"account", "chainID", "chainSet", "denomination"}, -) - -func (b *balanceMonitor) updateProm(acc solana.PublicKey, lamports uint64) { - v := solanaRelay.LamportsToSol(lamports) // convert from lamports to SOL - promSolanaBalance.WithLabelValues(acc.String(), b.chainID, "solana", "SOL").Set(v) -} diff --git a/core/chains/solana/monitor/prom_test.go b/core/chains/solana/monitor/prom_test.go deleted file mode 100644 index d1646e36874..00000000000 --- a/core/chains/solana/monitor/prom_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package monitor - -import ( - "testing" - - "github.com/gagliardetto/solana-go" - "github.com/prometheus/client_golang/prometheus/testutil" - "github.com/stretchr/testify/assert" -) - -func TestPromSolBalance(t *testing.T) { - key := solana.PublicKey{} - balance := uint64(1_000_000_000) - - monitor := balanceMonitor{chainID: "test-chain"} - monitor.updateProm(key, balance) - - // happy path test - promBalance := testutil.ToFloat64(promSolanaBalance.WithLabelValues(key.String(), monitor.chainID, "solana", "SOL")) - assert.Equal(t, float64(balance)/float64(solana.LAMPORTS_PER_SOL), promBalance) -} diff --git a/core/chains/starknet/chain.go b/core/chains/starknet/chain.go deleted file mode 100644 index fead94cda60..00000000000 --- a/core/chains/starknet/chain.go +++ /dev/null @@ -1,219 +0,0 @@ -package starknet - -import ( - "context" - "fmt" - "math/big" - "math/rand" - - "github.com/pkg/errors" - "go.uber.org/multierr" - "golang.org/x/exp/maps" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - starkChain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" - starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm" - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/starknet" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/chains/internal" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type ChainOpts struct { - Logger logger.Logger - // the implementation used here needs to be co-ordinated with the starknet transaction manager keystore adapter - KeyStore loop.Keystore -} - -func (o *ChainOpts) Name() string { - return o.Logger.Name() -} - -func (o *ChainOpts) Validate() (err error) { - required := func(s string) error { - return errors.Errorf("%s is required", s) - } - if o.Logger == nil { - err = multierr.Append(err, required("Logger'")) - } - if o.KeyStore == nil { - err = multierr.Append(err, required("KeyStore")) - } - return -} - -var _ starkChain.Chain = (*chain)(nil) - -type chain struct { - utils.StartStopOnce - id string - cfg *StarknetConfig - lggr logger.Logger - txm txm.StarkTXM -} - -func NewChain(cfg *StarknetConfig, opts ChainOpts) (starkchain.Chain, error) { - if !cfg.IsEnabled() { - return nil, fmt.Errorf("cannot create new chain with ID %s: %w", *cfg.ChainID, chains.ErrChainDisabled) - } - c, err := newChain(*cfg.ChainID, cfg, opts.KeyStore, opts.Logger) - if err != nil { - return nil, err - } - return c, nil -} - -func newChain(id string, cfg *StarknetConfig, loopKs loop.Keystore, lggr logger.Logger) (*chain, error) { - lggr = logger.With(lggr, "starknetChainID", id) - ch := &chain{ - id: id, - cfg: cfg, - lggr: logger.Named(lggr, "Chain"), - } - - getClient := func() (*starknet.Client, error) { - return ch.getClient() - } - - var err error - ch.txm, err = txm.New(lggr, loopKs, cfg, getClient) - if err != nil { - return nil, err - } - - return ch, nil -} - -func (c *chain) Name() string { - return c.lggr.Name() -} - -func (c *chain) Config() config.Config { - return c.cfg -} - -func (c *chain) TxManager() txm.TxManager { - return c.txm -} - -func (c *chain) Reader() (starknet.Reader, error) { - return c.getClient() -} - -func (c *chain) ChainID() relay.ChainID { - return relay.ChainID(c.id) -} - -// getClient returns a client, randomly selecting one from available and valid nodes -func (c *chain) getClient() (*starknet.Client, error) { - var node db.Node - var client *starknet.Client - nodes, err := c.cfg.ListNodes() - if err != nil { - return nil, errors.Wrap(err, "failed to get nodes") - } - if len(nodes) == 0 { - return nil, errors.New("no nodes available") - } - // #nosec - index := rand.Perm(len(nodes)) // list of node indexes to try - timeout := c.cfg.RequestTimeout() - for _, i := range index { - node = nodes[i] - // create client and check - client, err = starknet.NewClient(node.ChainID, node.URL, c.lggr, &timeout) - // if error, try another node - if err != nil { - c.lggr.Warnw("failed to create node", "name", node.Name, "starknet-url", node.URL, "err", err.Error()) - continue - } - // if all checks passed, mark found and break loop - break - } - // if no valid node found, exit with error - if client == nil { - return nil, errors.New("no node valid nodes available") - } - c.lggr.Debugw("Created client", "name", node.Name, "starknet-url", node.URL) - return client, nil -} - -func (c *chain) Start(ctx context.Context) error { - return c.StartOnce("Chain", func() error { - return c.txm.Start(ctx) - }) -} - -func (c *chain) Close() error { - return c.StopOnce("Chain", func() error { - return c.txm.Close() - }) -} - -func (c *chain) Ready() error { - return c.StartStopOnce.Ready() -} - -func (c *chain) HealthReport() map[string]error { - report := map[string]error{c.Name(): c.StartStopOnce.Healthy()} - maps.Copy(report, c.txm.HealthReport()) - return report -} - -func (c *chain) ID() string { - return c.id -} - -// ChainService interface -func (c *chain) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - toml, err := c.cfg.TOMLString() - if err != nil { - return relaytypes.ChainStatus{}, err - } - return relaytypes.ChainStatus{ - ID: c.id, - Enabled: c.cfg.IsEnabled(), - Config: toml, - }, nil -} - -func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return internal.ListNodeStatuses(int(pageSize), pageToken, c.listNodeStatuses) -} - -func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported -} - -func (c *chain) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return c.Transact(ctx, from, to, amount, balanceCheck) -} - -// TODO BCF-2602 statuses are static for non-evm chain and should be dynamic -func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { - stats := make([]relaytypes.NodeStatus, 0) - total := len(c.cfg.Nodes) - if start >= total { - return stats, total, internal.ErrOutOfRange - } - if end <= 0 || end > total { - end = total - } - nodes := c.cfg.Nodes[start:end] - for _, node := range nodes { - stat, err := nodeStatus(node, c.ChainID()) - if err != nil { - return stats, total, err - } - stats = append(stats, stat) - } - return stats, total, nil -} diff --git a/core/chains/starknet/config.go b/core/chains/starknet/config.go deleted file mode 100644 index 33b2a8d257a..00000000000 --- a/core/chains/starknet/config.go +++ /dev/null @@ -1,213 +0,0 @@ -package starknet - -import ( - "fmt" - "net/url" - "time" - - "github.com/pelletier/go-toml/v2" - "go.uber.org/multierr" - "golang.org/x/exp/slices" - - "github.com/smartcontractkit/chainlink-relay/pkg/types" - - stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/db" - - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" -) - -type StarknetConfigs []*StarknetConfig - -func (cs StarknetConfigs) ValidateConfig() (err error) { - return cs.validateKeys() -} - -func (cs StarknetConfigs) validateKeys() (err error) { - // Unique chain IDs - chainIDs := config.UniqueStrings{} - for i, c := range cs { - if chainIDs.IsDupe(c.ChainID) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), *c.ChainID)) - } - } - - // Unique node names - names := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - if names.IsDupe(n.Name) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), *n.Name)) - } - } - } - - // Unique URLs - urls := config.UniqueStrings{} - for i, c := range cs { - for j, n := range c.Nodes { - u := (*url.URL)(n.URL) - if urls.IsDupeFmt(u) { - err = multierr.Append(err, config.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.URL", i, j), u.String())) - } - } - } - return -} - -func (cs *StarknetConfigs) SetFrom(fs *StarknetConfigs) (err error) { - if err1 := fs.validateKeys(); err1 != nil { - return err1 - } - for _, f := range *fs { - if f.ChainID == nil { - *cs = append(*cs, f) - } else if i := slices.IndexFunc(*cs, func(c *StarknetConfig) bool { - return c.ChainID != nil && *c.ChainID == *f.ChainID - }); i == -1 { - *cs = append(*cs, f) - } else { - (*cs)[i].SetFrom(f) - } - } - return -} - -func nodeStatus(n *stkcfg.Node, id relay.ChainID) (types.NodeStatus, error) { - var s types.NodeStatus - s.ChainID = id - s.Name = *n.Name - b, err := toml.Marshal(n) - if err != nil { - return types.NodeStatus{}, err - } - s.Config = string(b) - return s, nil -} - -type StarknetConfig struct { - ChainID *string - // Do not access directly. Use [IsEnabled] - Enabled *bool - stkcfg.Chain - Nodes StarknetNodes -} - -func (c *StarknetConfig) IsEnabled() bool { - return c.Enabled == nil || *c.Enabled -} - -func (c *StarknetConfig) SetFrom(f *StarknetConfig) { - if f.ChainID != nil { - c.ChainID = f.ChainID - } - if f.Enabled != nil { - c.Enabled = f.Enabled - } - setFromChain(&c.Chain, &f.Chain) - c.Nodes.SetFrom(&f.Nodes) -} - -func setFromChain(c, f *stkcfg.Chain) { - if f.OCR2CachePollPeriod != nil { - c.OCR2CachePollPeriod = f.OCR2CachePollPeriod - } - if f.OCR2CacheTTL != nil { - c.OCR2CacheTTL = f.OCR2CacheTTL - } - if f.RequestTimeout != nil { - c.RequestTimeout = f.RequestTimeout - } - if f.TxTimeout != nil { - c.TxTimeout = f.TxTimeout - } - if f.ConfirmationPoll != nil { - c.ConfirmationPoll = f.ConfirmationPoll - } -} - -func (c *StarknetConfig) ValidateConfig() (err error) { - if c.ChainID == nil { - err = multierr.Append(err, config.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) - } else if *c.ChainID == "" { - err = multierr.Append(err, config.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) - } - - if len(c.Nodes) == 0 { - err = multierr.Append(err, config.ErrMissing{Name: "Nodes", Msg: "must have at least one node"}) - } - - return -} - -func (c *StarknetConfig) TOMLString() (string, error) { - b, err := toml.Marshal(c) - if err != nil { - return "", err - } - return string(b), nil -} - -type StarknetNodes []*stkcfg.Node - -func (ns *StarknetNodes) SetFrom(fs *StarknetNodes) { - for _, f := range *fs { - if f.Name == nil { - *ns = append(*ns, f) - } else if i := slices.IndexFunc(*ns, func(n *stkcfg.Node) bool { - return n.Name != nil && *n.Name == *f.Name - }); i == -1 { - *ns = append(*ns, f) - } else { - setFromNode((*ns)[i], f) - } - } -} - -func setFromNode(n, f *stkcfg.Node) { - if f.Name != nil { - n.Name = f.Name - } - if f.URL != nil { - n.URL = f.URL - } -} - -func legacyNode(n *stkcfg.Node, id relay.ChainID) db.Node { - return db.Node{ - Name: *n.Name, - ChainID: id, - URL: (*url.URL)(n.URL).String(), - } -} - -var _ stkcfg.Config = &StarknetConfig{} - -func (c *StarknetConfig) TxTimeout() time.Duration { - return c.Chain.TxTimeout.Duration() -} - -func (c *StarknetConfig) ConfirmationPoll() time.Duration { - return c.Chain.ConfirmationPoll.Duration() -} - -func (c *StarknetConfig) OCR2CachePollPeriod() time.Duration { - return c.Chain.OCR2CachePollPeriod.Duration() -} - -func (c *StarknetConfig) OCR2CacheTTL() time.Duration { - return c.Chain.OCR2CacheTTL.Duration() -} - -func (c *StarknetConfig) RequestTimeout() time.Duration { - return c.Chain.RequestTimeout.Duration() -} - -func (c *StarknetConfig) ListNodes() ([]db.Node, error) { - var allNodes []db.Node - for _, n := range c.Nodes { - allNodes = append(allNodes, legacyNode(n, *c.ChainID)) - } - return allNodes, nil -} diff --git a/core/cmd/admin_commands.go b/core/cmd/admin_commands.go index 6ff7a5f6312..24e78e5e2bb 100644 --- a/core/cmd/admin_commands.go +++ b/core/cmd/admin_commands.go @@ -204,7 +204,7 @@ func (s *Shell) CreateUser(c *cli.Context) (err error) { }() var links jsonapi.Links var users AdminUsersPresenters - if err := s.deserializeAPIResponse(resp, &users, &links); err != nil { + if err = s.deserializeAPIResponse(resp, &users, &links); err != nil { return s.errorOut(err) } for _, user := range users { @@ -316,8 +316,7 @@ func (s *Shell) Profile(c *cli.Context) error { genDir := filepath.Join(baseDir, fmt.Sprintf("debuginfo-%s", time.Now().Format(time.RFC3339))) - err := os.Mkdir(genDir, 0o755) - if err != nil { + if err := os.Mkdir(genDir, 0o755); err != nil { return s.errorOut(err) } var wgPprof sync.WaitGroup @@ -359,9 +358,9 @@ func (s *Shell) Profile(c *cli.Context) error { // best effort to interpret the underlying problem pprofVersion := resp.Header.Get("X-Go-Pprof") if pprofVersion == "1" { - b, err := io.ReadAll(resp.Body) - if err != nil { - errs <- fmt.Errorf("error collecting %s: %w", vt, errBadRequest) + b, err2 := io.ReadAll(resp.Body) + if err2 != nil { + errs <- fmt.Errorf("error collecting %s: %w", vt, err2) return } respContent := string(b) diff --git a/core/cmd/cosmos_node_commands_test.go b/core/cmd/cosmos_node_commands_test.go index 93364b74e0b..c19749ecd12 100644 --- a/core/cmd/cosmos_node_commands_test.go +++ b/core/cmd/cosmos_node_commands_test.go @@ -6,11 +6,12 @@ import ( "testing" "github.com/pelletier/go-toml/v2" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" - "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" + "github.com/smartcontractkit/chainlink-relay/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" diff --git a/core/testdata/tomlspecs/direct-request-spec.toml b/core/cmd/direct-request-spec-template.yml similarity index 79% rename from core/testdata/tomlspecs/direct-request-spec.toml rename to core/cmd/direct-request-spec-template.yml index 35c0cc9274e..5774e9a7933 100644 --- a/core/testdata/tomlspecs/direct-request-spec.toml +++ b/core/cmd/direct-request-spec-template.yml @@ -1,9 +1,9 @@ type = "directrequest" schemaVersion = 1 evmChainID = "0" -name = "example eth request event spec" +name = "%s" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" +externalJobID = "%s" observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; ds1_merge [type=merge left="{}"] diff --git a/core/cmd/eth_keys_commands.go b/core/cmd/eth_keys_commands.go index e5f1f025966..c13bea80f2f 100644 --- a/core/cmd/eth_keys_commands.go +++ b/core/cmd/eth_keys_commands.go @@ -41,7 +41,7 @@ func initEthKeysSubCmd(s *Shell) cli.Command { }, { Name: "list", - Usage: "List available Ethereum accounts with their ETH & LINK balances, nonces, and other metadata", + Usage: "List available Ethereum accounts with their ETH & LINK balances and other metadata", Action: s.ListETHKeys, }, { @@ -100,10 +100,6 @@ func initEthKeysSubCmd(s *Shell) cli.Command { Usage: "chain ID of the key", Required: true, }, - cli.Uint64Flag{ - Name: "set-next-nonce, setNextNonce", - Usage: "manually set the next nonce for the key on the given chain. This should not be necessary during normal operation. USE WITH CAUTION: Setting this incorrectly can break your node", - }, cli.BoolFlag{ Name: "enable", Usage: "enable the key for the given chain", @@ -130,7 +126,6 @@ func (p *EthKeyPresenter) ToRow() []string { return []string{ p.Address, p.EVMChainID.String(), - fmt.Sprintf("%d", p.NextNonce), p.EthBalance.String(), p.LinkBalance.String(), fmt.Sprintf("%v", p.Disabled), @@ -140,7 +135,7 @@ func (p *EthKeyPresenter) ToRow() []string { } } -var ethKeysTableHeaders = []string{"Address", "EVM Chain ID", "Next Nonce", "ETH", "LINK", "Disabled", "Created", "Updated", "Max Gas Price Wei"} +var ethKeysTableHeaders = []string{"Address", "EVM Chain ID", "ETH", "LINK", "Disabled", "Created", "Updated", "Max Gas Price Wei"} // RenderTable implements TableRenderer func (p *EthKeyPresenter) RenderTable(rt RendererTable) error { @@ -368,9 +363,6 @@ func (s *Shell) UpdateChainEVMKey(c *cli.Context) (err error) { abandon := c.String("abandon") query.Set("abandon", abandon) - if c.IsSet("set-next-nonce") { - query.Set("nextNonce", c.String("set-next-nonce")) - } if c.IsSet("enable") && c.IsSet("disable") { return s.errorOut(errors.New("cannot set both --enable and --disable simultaneously")) } else if c.Bool("enable") { diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 30e115e9482..630e76783a2 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -90,6 +90,7 @@ func TestShell_ListETHKeys(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(13), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -114,6 +115,7 @@ func TestShell_ListETHKeys_Error(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("fake error")) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("fake error")) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -156,7 +158,7 @@ func TestShell_ListETHKeys_Disabled(t *testing.T) { assert.Nil(t, balances[0].LinkBalance) assert.Nil(t, balances[0].MaxGasPriceWei) assert.Equal(t, []string{ - k.Address.String(), "0", "0", "", "0", "false", + k.Address.String(), "0", "", "0", "false", balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "", }, balances[0].ToRow()) } @@ -167,6 +169,8 @@ func TestShell_CreateETHKey(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) + app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -240,6 +244,7 @@ func TestShell_ImportExportETHKey_NoChains(t *testing.T) { ethClient := newEthMock(t) ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(42), nil) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(assets.NewLinkFromJuels(42), nil) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -343,6 +348,7 @@ func TestShell_ImportExportETHKey_WithChains(t *testing.T) { t.Cleanup(func() { deleteKeyExportFile(t) }) ethClient := newEthMock(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index eb421b03968..484b1ccd3da 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -29,7 +29,7 @@ func TestShell_IndexTransactions(t *testing.T) { app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -70,7 +70,7 @@ func TestShell_ShowTransaction(t *testing.T) { client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, db, app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -94,7 +94,7 @@ func TestShell_IndexTxAttempts(t *testing.T) { app := startNewApplicationV2(t, nil) client, r := app.NewShellAndRenderer() - _, from := cltest.MustAddRandomKeyToKeystore(t, app.KeyStore.Eth()) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) tx := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) @@ -140,6 +140,7 @@ func TestShell_SendEther_From_Txm(t *testing.T) { ethMock.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) ethMock.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Maybe() + ethMock.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) @@ -199,6 +200,7 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { ethMock.On("BalanceAt", mock.Anything, key.Address, (*big.Int)(nil)).Return(balance.ToInt(), nil) ethMock.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Maybe() + ethMock.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) diff --git a/core/cmd/forwarders_commands_test.go b/core/cmd/forwarders_commands_test.go index 4381b5ca683..b08d94f64dc 100644 --- a/core/cmd/forwarders_commands_test.go +++ b/core/cmd/forwarders_commands_test.go @@ -6,7 +6,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli" @@ -23,7 +22,7 @@ func TestEVMForwarderPresenter_RenderTable(t *testing.T) { var ( id = "1" - address = common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") + address = utils.RandomAddress() evmChainID = utils.NewBigI(4) createdAt = time.Now() updatedAt = time.Now().Add(time.Second) @@ -76,7 +75,7 @@ func TestShell_TrackEVMForwarder(t *testing.T) { set := flag.NewFlagSet("test", 0) cltest.FlagSetApplyFromAction(client.TrackForwarder, set, "") - require.NoError(t, set.Set("address", "0x5431F5F973781809D18643b87B44921b11355d81")) + require.NoError(t, set.Set("address", utils.RandomAddress().Hex())) require.NoError(t, set.Set("evm-chain-id", id.String())) err := client.TrackForwarder(cli.NewContext(nil, set, nil)) diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index 29d0d8da706..b83b17f0be6 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -2,10 +2,13 @@ package cmd_test import ( "bytes" + _ "embed" "flag" + "fmt" "testing" "time" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli" @@ -293,6 +296,13 @@ func TestJob_ToRows(t *testing.T) { }, job.ToRows()) } +//go:embed direct-request-spec-template.yml +var directRequestSpecTemplate string + +func getDirectRequestSpec() string { + return fmt.Sprintf(directRequestSpecTemplate, uuid.New(), uuid.New()) +} + func TestShell_ListFindJobs(t *testing.T) { t.Parallel() @@ -305,7 +315,7 @@ func TestShell_ListFindJobs(t *testing.T) { fs := flag.NewFlagSet("", flag.ExitOnError) cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") - require.NoError(t, fs.Parse([]string{"../testdata/tomlspecs/direct-request-spec.toml"})) + require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) err := client.CreateJob(cli.NewContext(nil, fs, nil)) require.NoError(t, err) @@ -331,7 +341,7 @@ func TestShell_ShowJob(t *testing.T) { fs := flag.NewFlagSet("", flag.ExitOnError) cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") - require.NoError(t, fs.Parse([]string{"../testdata/tomlspecs/direct-request-spec.toml"})) + require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) err := client.CreateJob(cli.NewContext(nil, fs, nil)) require.NoError(t, err) @@ -349,6 +359,9 @@ func TestShell_ShowJob(t *testing.T) { assert.Equal(t, createOutput.ID, job.ID) } +//go:embed ocr-bootstrap-spec.yml +var ocrBootstrapSpec string + func TestShell_CreateJobV2(t *testing.T) { t.Parallel() @@ -371,7 +384,9 @@ func TestShell_CreateJobV2(t *testing.T) { fs := flag.NewFlagSet("", flag.ExitOnError) cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") - require.NoError(t, fs.Parse([]string{"../testdata/tomlspecs/ocr-bootstrap-spec.toml"})) + nameAndExternalJobID := uuid.New() + spec := fmt.Sprintf(ocrBootstrapSpec, nameAndExternalJobID, nameAndExternalJobID) + require.NoError(t, fs.Parse([]string{spec})) err := client.CreateJob(cli.NewContext(nil, fs, nil)) require.NoError(t, err) @@ -400,7 +415,7 @@ func TestShell_DeleteJob(t *testing.T) { fs := flag.NewFlagSet("", flag.ExitOnError) cltest.FlagSetApplyFromAction(client.CreateJob, fs, "") - require.NoError(t, fs.Parse([]string{"../testdata/tomlspecs/direct-request-spec.toml"})) + require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) err := client.CreateJob(cli.NewContext(nil, fs, nil)) require.NoError(t, err) diff --git a/core/cmd/mocks/prompter.go b/core/cmd/mocks/prompter.go index 0507eb60ab5..c0f682d5b9f 100644 --- a/core/cmd/mocks/prompter.go +++ b/core/cmd/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -51,13 +51,12 @@ func (_m *Prompter) Prompt(_a0 string) string { return r0 } -type mockConstructorTestingTNewPrompter interface { +// NewPrompter creates a new instance of Prompter. 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 NewPrompter(t interface { mock.TestingT Cleanup(func()) -} - -// NewPrompter creates a new instance of Prompter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewPrompter(t mockConstructorTestingTNewPrompter) *Prompter { +}) *Prompter { mock := &Prompter{} mock.Mock.Test(t) diff --git a/core/testdata/tomlspecs/ocr-bootstrap-spec.toml b/core/cmd/ocr-bootstrap-spec.yml similarity index 76% rename from core/testdata/tomlspecs/ocr-bootstrap-spec.toml rename to core/cmd/ocr-bootstrap-spec.yml index 9df0a861960..9db118b77cd 100644 --- a/core/testdata/tomlspecs/ocr-bootstrap-spec.toml +++ b/core/cmd/ocr-bootstrap-spec.yml @@ -1,9 +1,10 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F50" +externalJobID = "%s" +name = "%s" evmChainID = "0" p2pBootstrapPeers = [ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", ] -isBootstrapPeer = true \ No newline at end of file +isBootstrapPeer = true diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index 01bfd89c32b..a3feddd611d 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -14,6 +14,8 @@ import ( "github.com/pkg/errors" "github.com/urfave/cli" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -202,47 +204,12 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e } if useForwarder { - // Replace the transmitter ID with the forwarder address. - forwarderAddress := c.String("forwarder-address") - - ks := app.GetKeyStore().Eth() - // Add extra sending keys if using a forwarder. - for i := 0; i < forwarderAdditionalEOACount; i++ { - - // Create the sending key in the keystore. - k, err := ks.Create() - if err != nil { - return nil, err - } - - // Enable the sending key for the current chain. - err = ks.Enable(k.Address, big.NewInt(chainID)) - if err != nil { - return nil, err - } - - sendingKeys = append(sendingKeys, k.Address.String()) - sendingKeysAddresses = append(sendingKeysAddresses, k.Address) - } - - // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the - // forwarder will not be recognized. - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) - defer cancel() - f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) - tx, err := f.SetAuthorizedSenders(owner, sendingKeysAddresses) + sendingKeys, sendingKeysAddresses, err = s.appendForwarders(chainID, app.GetKeyStore().Eth(), sendingKeys, sendingKeysAddresses) if err != nil { return nil, err } - _, err = bind.WaitMined(ctx, ec, tx) - if err != nil { - return nil, err - } - - // Create forwarder for management in forwarder_manager.go. - orm := forwarders.NewORM(ldb.DB(), lggr, s.Config.Database()) - _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + err = s.authorizeForwarder(c, ldb.DB(), lggr, chainID, ec, owner, sendingKeysAddresses) if err != nil { return nil, err } @@ -331,9 +298,60 @@ func (s *Shell) ConfigureOCR2VRFNode(c *cli.Context, owner *bind.TransactOpts, e }, nil } -func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Master) error { - err := cli.KeyStoreAuthenticator.authenticate(keyStore, cli.Config.Password()) +func (s *Shell) appendForwarders(chainID int64, ks keystore.Eth, sendingKeys []string, sendingKeysAddresses []common.Address) ([]string, []common.Address, error) { + for i := 0; i < forwarderAdditionalEOACount; i++ { + // Create the sending key in the keystore. + k, err := ks.Create() + if err != nil { + return nil, nil, err + } + + // Enable the sending key for the current chain. + err = ks.Enable(k.Address, big.NewInt(chainID)) + if err != nil { + return nil, nil, err + } + + sendingKeys = append(sendingKeys, k.Address.String()) + sendingKeysAddresses = append(sendingKeysAddresses, k.Address) + } + + return sendingKeys, sendingKeysAddresses, nil +} + +func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logger, chainID int64, ec *ethclient.Client, owner *bind.TransactOpts, sendingKeysAddresses []common.Address) error { + // Replace the transmitter ID with the forwarder address. + forwarderAddress := c.String("forwarder-address") + + // We have to set the authorized senders on-chain here, otherwise the job spawner will fail as the + // forwarder will not be recognized. + ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) + defer cancel() + f, err := authorized_forwarder.NewAuthorizedForwarder(common.HexToAddress(forwarderAddress), ec) if err != nil { + return err + } + tx, err := f.SetAuthorizedSenders(owner, sendingKeysAddresses) + if err != nil { + return err + } + _, err = bind.WaitMined(ctx, ec, tx) + if err != nil { + return err + } + + // Create forwarder for management in forwarder_manager.go. + orm := forwarders.NewORM(db, lggr, s.Config.Database()) + _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + if err != nil { + return err + } + + return nil +} + +func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Master) error { + if err := cli.KeyStoreAuthenticator.authenticate(keyStore, cli.Config.Password()); err != nil { return errors.Wrap(err, "error authenticating keystore") } @@ -363,19 +381,19 @@ func setupKeystore(cli *Shell, app chainlink.Application, keyStore keystore.Mast enabledChains = append(enabledChains, chaintype.StarkNet) } - if err = keyStore.OCR2().EnsureKeys(enabledChains...); err != nil { + if err := keyStore.OCR2().EnsureKeys(enabledChains...); err != nil { return errors.Wrap(err, "failed to ensure ocr key") } - if err = keyStore.DKGSign().EnsureKey(); err != nil { + if err := keyStore.DKGSign().EnsureKey(); err != nil { return errors.Wrap(err, "failed to ensure dkgsign key") } - if err = keyStore.DKGEncrypt().EnsureKey(); err != nil { + if err := keyStore.DKGEncrypt().EnsureKey(); err != nil { return errors.Wrap(err, "failed to ensure dkgencrypt key") } - if err = keyStore.P2P().EnsureKey(); err != nil { + if err := keyStore.P2P().EnsureKey(); err != nil { return errors.Wrap(err, "failed to ensure p2p key") } diff --git a/core/cmd/renderer_test.go b/core/cmd/renderer_test.go index f617747953c..91f5650caa8 100644 --- a/core/cmd/renderer_test.go +++ b/core/cmd/renderer_test.go @@ -37,7 +37,7 @@ func TestRendererTable_RenderConfigurationV2(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) wantUser, wantEffective := app.Config.ConfigTOML() require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) t.Run("effective", func(t *testing.T) { resp, cleanup := client.Get("/v2/config/v2") diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 8532f2f5431..fbbce4becbc 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -60,12 +60,20 @@ var ( grpcOpts loop.GRPCOpts ) -func initGlobals(cfg config.Prometheus) { - // Avoid double initializations. +func initGlobals(cfgProm config.Prometheus, cfgTracing config.Tracing) error { + // Avoid double initializations, but does not prevent relay methods from being called multiple times. + var err error initGlobalsOnce.Do(func() { - prometheus = ginprom.New(ginprom.Namespace("service"), ginprom.Token(cfg.AuthToken())) - grpcOpts = loop.SetupTelemetry(nil) // default prometheus.Registerer + prometheus = ginprom.New(ginprom.Namespace("service"), ginprom.Token(cfgProm.AuthToken())) + grpcOpts = loop.NewGRPCOpts(nil) // default prometheus.Registerer + err = loop.SetupTracing(loop.TracingConfig{ + Enabled: cfgTracing.Enabled(), + CollectorTarget: cfgTracing.CollectorTarget(), + NodeAttributes: cfgTracing.Attributes(), + SamplingRatio: cfgTracing.SamplingRatio(), + }) }) + return err } var ( @@ -126,7 +134,10 @@ type ChainlinkAppFactory struct{} // NewApplication returns a new instance of the node with the given config. func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.GeneralConfig, appLggr logger.Logger, db *sqlx.DB) (app chainlink.Application, err error) { - initGlobals(cfg.Prometheus()) + err = initGlobals(cfg.Prometheus(), cfg.Tracing()) + if err != nil { + appLggr.Errorf("Failed to initialize globals: %v", err) + } err = migrate.SetMigrationENVVars(cfg) if err != nil { @@ -143,7 +154,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G dbListener := cfg.Database().Listener() eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), dbListener.MinReconnectInterval(), dbListener.MaxReconnectDuration(), appLggr, cfg.AppID()) - loopRegistry := plugins.NewLoopRegistry(appLggr) + loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) // create the relayer-chain interoperators from application configuration relayerFactory := chainlink.RelayerFactory{ @@ -170,15 +181,15 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G } if cfg.SolanaEnabled() { solanaCfg := chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - SolanaConfigs: cfg.SolanaConfigs(), + Keystore: keyStore.Solana(), + TOMLConfigs: cfg.SolanaConfigs(), } initOps = append(initOps, chainlink.InitSolana(ctx, relayerFactory, solanaCfg)) } if cfg.StarkNetEnabled() { starkCfg := chainlink.StarkNetFactoryConfig{ - Keystore: keyStore.StarkNet(), - StarknetConfigs: cfg.StarknetConfigs(), + Keystore: keyStore.StarkNet(), + TOMLConfigs: cfg.StarknetConfigs(), } initOps = append(initOps, chainlink.InitStarknet(ctx, relayerFactory, starkCfg)) @@ -997,8 +1008,7 @@ func confirmAction(c *cli.Context) bool { return true } else if answer == "no" { return false - } else { - fmt.Printf("%s is not valid. Please type yes or no\n", answer) } + fmt.Printf("%s is not valid. Please type yes or no\n", answer) } } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 372aad01384..401375238d8 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -37,7 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" @@ -46,6 +45,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/migrate" "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/web" webPresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -290,10 +290,9 @@ func (s *Shell) runNode(c *cli.Context) error { s.Config.SetPasswords(pwd, vrfpwd) - s.Config.LogConfiguration(lggr.Debugf) + s.Config.LogConfiguration(lggr.Debugf, lggr.Warnf) - err := s.Config.Validate() - if err != nil { + if err := s.Config.Validate(); err != nil { return errors.Wrap(err, "config validation failed") } @@ -373,9 +372,9 @@ func (s *Shell) runNode(c *cli.Context) error { legacyEVMChains := app.GetRelayers().LegacyEVMChains() if s.Config.EVMEnabled() { - chainList, err := legacyEVMChains.List() - if err != nil { - return fmt.Errorf("error listing legacy evm chains: %w", err) + chainList, err2 := legacyEVMChains.List() + if err2 != nil { + return fmt.Errorf("error listing legacy evm chains: %w", err2) } for _, ch := range chainList { if ch.Config().EVM().AutoCreateKey() { @@ -500,8 +499,7 @@ func (s *Shell) runNode(c *cli.Context) error { func checkFilePermissions(lggr logger.Logger, rootDir string) error { // Ensure tls sub directory (and children) permissions are <= `ownerPermsMask`` tlsDir := filepath.Join(rootDir, "tls") - _, err := os.Stat(tlsDir) - if err != nil && !os.IsNotExist(err) { + if _, err := os.Stat(tlsDir); err != nil && !os.IsNotExist(err) { lggr.Errorf("error checking perms of 'tls' directory: %v", err) } else if err == nil { err := utils.EnsureDirAndMaxPerms(tlsDir, ownerPermsMask) @@ -610,9 +608,9 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { } if c.IsSet("password") { - pwd, err := utils.PasswordFromFile(c.String("password")) - if err != nil { - return s.errorOut(fmt.Errorf("error reading password: %+v", err)) + pwd, err2 := utils.PasswordFromFile(c.String("password")) + if err2 != nil { + return s.errorOut(fmt.Errorf("error reading password: %+v", err2)) } s.Config.SetPasswords(&pwd, nil) } @@ -658,9 +656,9 @@ func (p *HealthCheckPresenter) ToRow() []string { var status string switch p.Status { - case services.StatusFailing: + case web.HealthStatusFailing: status = red(p.Status) - case services.StatusPassing: + case web.HealthStatusPassing: status = green(p.Status) } @@ -691,7 +689,8 @@ var errDBURLMissing = errors.New("You must set CL_DATABASE_URL env variable or p // ConfigValidate validate the client configuration and pretty-prints results func (s *Shell) ConfigFileValidate(_ *cli.Context) error { - s.Config.LogConfiguration(func(f string, params ...any) { fmt.Printf(f, params...) }) + fn := func(f string, params ...any) { fmt.Printf(f, params...) } + s.Config.LogConfiguration(fn, fn) if err := s.configExitErr(s.Config.Validate); err != nil { return err } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 691e5faa923..be8d5c94056 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -42,7 +42,7 @@ import ( func genTestEVMRelayers(t *testing.T, opts evm.ChainRelayExtenderConfig, ks evmrelayer.CSAETHKeystore) *chainlink.CoreRelayerChainInteroperators { f := chainlink.RelayerFactory{ Logger: opts.Logger, - LoopRegistry: plugins.NewLoopRegistry(opts.Logger), + LoopRegistry: plugins.NewLoopRegistry(opts.Logger, opts.AppConfig.Tracing()), } relayers, err := chainlink.NewCoreRelayerChainInteroperators(chainlink.InitEVM(testutils.Context(t), f, chainlink.EVMFactoryConfig{ @@ -370,7 +370,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) txStore := cltest.NewTestTxStore(t, sqlxDB, config.Database()) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, int64(test.nonce), 42, fromAddress) @@ -448,7 +448,7 @@ func TestShell_RebroadcastTransactions_AddressCheck(t *testing.T) { keyStore := cltest.NewKeyStore(t, sqlxDB, config.Database()) - _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth(), 0) + _, fromAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) if !test.enableAddress { err := keyStore.Eth().Disable(fromAddress, testutils.FixtureChainID) diff --git a/core/cmd/shell_remote.go b/core/cmd/shell_remote.go index 9480d92604f..fa72d21ee6f 100644 --- a/core/cmd/shell_remote.go +++ b/core/cmd/shell_remote.go @@ -465,9 +465,9 @@ func parseResponse(resp *http.Response) ([]byte, error) { } else if resp.StatusCode == http.StatusForbidden { return b, errForbidden } else if resp.StatusCode >= http.StatusBadRequest { - errorMessage, err := parseErrorResponseBody(b) - if err != nil { - return b, err + errorMessage, err2 := parseErrorResponseBody(b) + if err2 != nil { + return b, err2 } return b, errors.New(errorMessage) } diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 83686443faa..c1d15df9ec8 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/google/uuid" "github.com/kylelemons/godebug/diff" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" @@ -220,7 +221,7 @@ func TestShell_DestroyExternalInitiator(t *testing.T) { token := auth.NewToken() exi, err := bridges.NewExternalInitiator(token, - &bridges.ExternalInitiatorRequest{Name: "name"}, + &bridges.ExternalInitiatorRequest{Name: uuid.New().String()}, ) require.NoError(t, err) err = app.BridgeORM().CreateExternalInitiator(exi) @@ -257,17 +258,20 @@ func TestShell_DestroyExternalInitiator_NotFound(t *testing.T) { func TestShell_RemoteLogin(t *testing.T) { app := startNewApplicationV2(t, nil) + orm := app.SessionORM() + + u := cltest.NewUserWithSession(t, orm) tests := []struct { name, file string email, pwd string wantError bool }{ - {"success prompt", "", cltest.APIEmailAdmin, cltest.Password, false}, + {"success prompt", "", u.Email, cltest.Password, false}, {"success file", "../internal/fixtures/apicredentials", "", "", false}, {"failure prompt", "", "wrong@email.com", "wrongpwd", true}, {"failure file", "/tmp/doesntexist", "", "", true}, - {"failure file w correct prompt", "/tmp/doesntexist", cltest.APIEmailAdmin, cltest.Password, true}, + {"failure file w correct prompt", "/tmp/doesntexist", u.Email, cltest.Password, true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -297,7 +301,8 @@ func TestShell_RemoteBuildCompatibility(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - enteredStrings := []string{cltest.APIEmailAdmin, cltest.Password} + u := cltest.NewUserWithSession(t, app.SessionORM()) + enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: append(enteredStrings, enteredStrings...)} client := app.NewAuthenticatingShell(prompter) @@ -335,6 +340,7 @@ func TestShell_CheckRemoteBuildCompatibility(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) + u := cltest.NewUserWithSession(t, app.SessionORM()) tests := []struct { name string remoteVersion, remoteSha string @@ -349,7 +355,7 @@ func TestShell_CheckRemoteBuildCompatibility(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - enteredStrings := []string{cltest.APIEmailAdmin, cltest.Password} + enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} client := app.NewAuthenticatingShell(prompter) @@ -410,8 +416,9 @@ func TestShell_ChangePassword(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) + u := cltest.NewUserWithSession(t, app.SessionORM()) - enteredStrings := []string{cltest.APIEmailAdmin, cltest.Password} + enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} client := app.NewAuthenticatingShell(prompter) @@ -459,7 +466,8 @@ func TestShell_Profile_InvalidSecondsParam(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - enteredStrings := []string{cltest.APIEmailAdmin, cltest.Password} + u := cltest.NewUserWithSession(t, app.SessionORM()) + enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} client := app.NewAuthenticatingShell(prompter) @@ -489,7 +497,8 @@ func TestShell_Profile(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, nil) - enteredStrings := []string{cltest.APIEmailAdmin, cltest.Password} + u := cltest.NewUserWithSession(t, app.SessionORM()) + enteredStrings := []string{u.Email, cltest.Password} prompter := &cltest.MockCountingPrompter{T: t, EnteredStrings: enteredStrings} client := app.NewAuthenticatingShell(prompter) @@ -656,7 +665,7 @@ func TestShell_AutoLogin(t *testing.T) { require.NoError(t, err) // Expire the session and then try again - pgtest.MustExec(t, app.GetSqlxDB(), "TRUNCATE sessions") + pgtest.MustExec(t, app.GetSqlxDB(), "delete from sessions where email = $1", user.Email) err = client.ListJobs(cli.NewContext(nil, fs, nil)) require.NoError(t, err) } diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index c74a0067a68..74768a21928 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -12,11 +12,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -33,13 +32,16 @@ import ( func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { t.Parallel() + app := cltest.NewApplicationEVMDisabled(t) + u := cltest.NewUserWithSession(t, app.SessionORM()) + tests := []struct { name, email, pwd string }{ {"bad email", "notreal", cltest.Password}, - {"bad pwd", cltest.APIEmailAdmin, "mostcommonwrongpwdever"}, + {"bad pwd", u.Email, "mostcommonwrongpwdever"}, {"bad both", "notreal", "mostcommonwrongpwdever"}, - {"correct", cltest.APIEmailAdmin, cltest.Password}, + {"correct", u.Email, cltest.Password}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -63,14 +65,16 @@ func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) + u := cltest.NewUserWithSession(t, app.SessionORM()) + tests := []struct { name, email, pwd string wantError bool }{ {"bad email", "notreal", cltest.Password, true}, - {"bad pwd", cltest.APIEmailAdmin, "mostcommonwrongpwdever", true}, + {"bad pwd", u.Email, "mostcommonwrongpwdever", true}, {"bad both", "notreal", "mostcommonwrongpwdever", true}, - {"success", cltest.APIEmailAdmin, cltest.Password, false}, + {"success", u.Email, cltest.Password, false}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -340,26 +344,26 @@ func TestNewUserCache(t *testing.T) { func TestSetupSolanaRelayer(t *testing.T) { lggr := logger.TestLogger(t) - reg := plugins.NewLoopRegistry(lggr) + reg := plugins.NewLoopRegistry(lggr, nil) ks := mocks.NewSolana(t) // config 3 chains but only enable 2 => should only be 2 relayer nEnabledChains := 2 tConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Solana = solana.SolanaConfigs{ - &solana.SolanaConfig{ + c.Solana = solana.TOMLConfigs{ + &solana.TOMLConfig{ ChainID: ptr[string]("solana-id-1"), Enabled: ptr(true), Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{}, }, - &solana.SolanaConfig{ + &solana.TOMLConfig{ ChainID: ptr[string]("solana-id-2"), Enabled: ptr(true), Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{}, }, - &solana.SolanaConfig{ + &solana.TOMLConfig{ ChainID: ptr[string]("disabled-solana-id-1"), Enabled: ptr(false), Chain: solcfg.Chain{}, @@ -396,14 +400,14 @@ func TestSetupSolanaRelayer(t *testing.T) { // test that duplicate enabled chains is an error when duplicateConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Solana = solana.SolanaConfigs{ - &solana.SolanaConfig{ + c.Solana = solana.TOMLConfigs{ + &solana.TOMLConfig{ ChainID: ptr[string]("dupe"), Enabled: ptr(true), Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{}, }, - &solana.SolanaConfig{ + &solana.TOMLConfig{ ChainID: ptr[string]("dupe"), Enabled: ptr(true), Chain: solcfg.Chain{}, @@ -427,25 +431,25 @@ func TestSetupSolanaRelayer(t *testing.T) { func TestSetupStarkNetRelayer(t *testing.T) { lggr := logger.TestLogger(t) - reg := plugins.NewLoopRegistry(lggr) + reg := plugins.NewLoopRegistry(lggr, nil) ks := mocks.NewStarkNet(t) // config 3 chains but only enable 2 => should only be 2 relayer nEnabledChains := 2 tConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Starknet = starknet.StarknetConfigs{ - &starknet.StarknetConfig{ + c.Starknet = stkcfg.TOMLConfigs{ + &stkcfg.TOMLConfig{ ChainID: ptr[string]("starknet-id-1"), Enabled: ptr(true), Chain: stkcfg.Chain{}, Nodes: []*config.Node{}, }, - &starknet.StarknetConfig{ + &stkcfg.TOMLConfig{ ChainID: ptr[string]("starknet-id-2"), Enabled: ptr(true), Chain: stkcfg.Chain{}, Nodes: []*config.Node{}, }, - &starknet.StarknetConfig{ + &stkcfg.TOMLConfig{ ChainID: ptr[string]("disabled-starknet-id-1"), Enabled: ptr(false), Chain: stkcfg.Chain{}, @@ -481,14 +485,14 @@ func TestSetupStarkNetRelayer(t *testing.T) { // test that duplicate enabled chains is an error when duplicateConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Starknet = starknet.StarknetConfigs{ - &starknet.StarknetConfig{ + c.Starknet = stkcfg.TOMLConfigs{ + &stkcfg.TOMLConfig{ ChainID: ptr[string]("dupe"), Enabled: ptr(true), Chain: stkcfg.Chain{}, Nodes: []*config.Node{}, }, - &starknet.StarknetConfig{ + &stkcfg.TOMLConfig{ ChainID: ptr[string]("dupe"), Enabled: ptr(true), Chain: stkcfg.Chain{}, diff --git a/core/cmd/solana_chains_commands_test.go b/core/cmd/solana_chains_commands_test.go index ac80b307d0a..88bc8049247 100644 --- a/core/cmd/solana_chains_commands_test.go +++ b/core/cmd/solana_chains_commands_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/solanatest" @@ -16,7 +16,7 @@ func TestShell_IndexSolanaChains(t *testing.T) { t.Parallel() id := solanatest.RandomChainID() - cfg := solana.SolanaConfig{ + cfg := solana.TOMLConfig{ ChainID: &id, Enabled: ptr(true), } diff --git a/core/cmd/solana_node_commands_test.go b/core/cmd/solana_node_commands_test.go index 48a889c0adf..3f95ebc0d84 100644 --- a/core/cmd/solana_node_commands_test.go +++ b/core/cmd/solana_node_commands_test.go @@ -12,14 +12,14 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/utils" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/solanatest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) -func solanaStartNewApplication(t *testing.T, cfgs ...*solana.SolanaConfig) *cltest.TestApplication { +func solanaStartNewApplication(t *testing.T, cfgs ...*solana.TOMLConfig) *cltest.TestApplication { for i := range cfgs { cfgs[i].SetDefaults() } @@ -41,7 +41,7 @@ func TestShell_IndexSolanaNodes(t *testing.T) { Name: ptr("second"), URL: utils.MustParseURL("https://solana2.example"), } - chain := solana.SolanaConfig{ + chain := solana.TOMLConfig{ ChainID: &id, Nodes: solana.SolanaNodes{&node1, &node2}, } diff --git a/core/cmd/solana_transaction_commands_test.go b/core/cmd/solana_transaction_commands_test.go index a23a3dce5c2..cdb182cba41 100644 --- a/core/cmd/solana_transaction_commands_test.go +++ b/core/cmd/solana_transaction_commands_test.go @@ -19,7 +19,7 @@ import ( solanaClient "github.com/smartcontractkit/chainlink-solana/pkg/solana/client" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) @@ -31,7 +31,7 @@ func TestShell_SolanaSendSol(t *testing.T) { Name: ptr(t.Name()), URL: utils.MustParseURL(url), } - cfg := solana.SolanaConfig{ + cfg := solana.TOMLConfig{ ChainID: &chainID, Nodes: solana.SolanaNodes{&node}, Enabled: ptr(true), diff --git a/core/cmd/starknet_node_commands_test.go b/core/cmd/starknet_node_commands_test.go index 7df7af429b5..e799e5aac07 100644 --- a/core/cmd/starknet_node_commands_test.go +++ b/core/cmd/starknet_node_commands_test.go @@ -12,13 +12,12 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) -func starknetStartNewApplication(t *testing.T, cfgs ...*starknet.StarknetConfig) *cltest.TestApplication { +func starknetStartNewApplication(t *testing.T, cfgs ...*config.TOMLConfig) *cltest.TestApplication { for i := range cfgs { cfgs[i].SetDefaults() } @@ -41,9 +40,9 @@ func TestShell_IndexStarkNetNodes(t *testing.T) { Name: ptr("second"), URL: utils.MustParseURL("https://starknet2.example"), } - chain := starknet.StarknetConfig{ + chain := config.TOMLConfig{ ChainID: &id, - Nodes: starknet.StarknetNodes{&node1, &node2}, + Nodes: config.Nodes{&node1, &node2}, } app := starknetStartNewApplication(t, &chain) client, r := app.NewShellAndRenderer() diff --git a/core/config/app_config.go b/core/config/app_config.go index 20e877e6ec1..648939b871b 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -28,7 +28,7 @@ type AppConfig interface { Validate() error ValidateDB() error - LogConfiguration(log LogfFn) + LogConfiguration(log, warn LogfFn) SetLogLevel(lvl zapcore.Level) error SetLogSQL(logSQL bool) SetPasswords(keystore, vrf *string) @@ -53,6 +53,7 @@ type AppConfig interface { TelemetryIngress() TelemetryIngress Threshold() Threshold WebServer() WebServer + Tracing() Tracing } type DatabaseBackupMode string diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 7517eff61be..c8b5395d6d7 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -311,6 +311,7 @@ PollInterval = '10s' # Default # SelectionMode controls node selection strategy: # - HighestHead: use the node with the highest head number # - RoundRobin: rotate through nodes, per-request +# - PriorityLevel: use the node with the smallest order number # - TotalDifficulty: use the node with the greatest total difficulty SelectionMode = 'HighestHead' # Default # SyncThreshold controls how far a node may lag behind the best node before being marked out-of-sync. @@ -318,6 +319,13 @@ SelectionMode = 'HighestHead' # Default # # Set to 0 to disable this check. SyncThreshold = 5 # Default +# LeaseDuration is the minimum duration that the selected "best" node (as defined by SelectionMode) will be used, +# before switching to a better one if available. It also controls how often the lease check is done. +# Setting this to a low value (under 1m) might cause RPC to switch too aggressively. +# Recommended value is over 5m +# +# Set to '0s' to disable +LeaseDuration = '0s' # Default [EVM.OCR] # ContractConfirmations sets `OCR.ContractConfirmations` for this EVM chain. diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index b9c1063c12a..1ca4c656a7f 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -88,9 +88,9 @@ LeaseRefreshInterval = '1s' # Default UniConn = true # Default # Logging toggles verbose logging of the raw telemetry messages being sent. Logging = false # Default -# ServerPubKey is the public key of the telemetry server. +# ServerPubKey is the public key of the telemetry server. This field will be removed in a furture version ServerPubKey = 'test-pub-key' # Example -# URL is where to send telemetry. +# URL is where to send telemetry. This field will be removed in a furture version URL = 'https://prom.test' # Example # BufferSize is the number of telemetry messages to buffer before dropping new ones. BufferSize = 100 # Default @@ -103,6 +103,16 @@ SendTimeout = '10s' # Default # UseBatchSend toggles sending telemetry to the ingress server using the batch client. UseBatchSend = true # Default +[[TelemetryIngress.Endpoints]] # Example +# Network aka EVM, Solana, Starknet +Network = 'EVM' # Example +# ChainID of the network +ChainID = '111551111' # Example +# ServerPubKey is the public key of the telemetry server. +ServerPubKey = 'test-pub-key-111551111-evm' # Example +# URL is where to send telemetry. +URL = 'localhost-111551111-evm:9000' # Example + [AuditLogger] # Enabled determines if this logger should be configured at all Enabled = false # Default @@ -349,6 +359,8 @@ TraceLogging = false # Default # automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful # for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. # +# Note: P2P.V1 is deprecated will be removed in the future. +# # All nodes in the OCR network should share the same networking stack. [P2P] # IncomingMessageBufferSize is the per-remote number of incoming @@ -367,9 +379,10 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example # TraceLogging enables trace level logging. TraceLogging = false # Default +# P2P.V1 is deprecated and will be removed in a future version. [P2P.V1] # Enabled enables P2P V1. -Enabled = true # Default +Enabled = false # Default # AnnounceIP should be set as the externally reachable IP address of the Chainlink node. AnnounceIP = '1.2.3.4' # Example # AnnouncePort should be set as the externally reachable port of the Chainlink node. @@ -413,7 +426,7 @@ PeerstoreWriteInterval = '5m' # Default [P2P.V2] # Enabled enables P2P V2. # Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. -Enabled = false # Default +Enabled = true # Default # AnnounceAddresses is the addresses the peer will advertise on the network in `host:port` form as accepted by the TCP version of Go’s `net.Dial`. # The addresses should be reachable by other nodes on the network. When attempting to connect to another node, # a node will attempt to dial all of the other node’s AnnounceAddresses in round-robin fashion. @@ -530,3 +543,17 @@ InfiniteDepthQueries = false # Default # DisableRateLimiting skips ratelimiting on asset requests. DisableRateLimiting = false # Default +[Tracing] +# Enabled turns trace collection on or off. On requires an OTEL Tracing Collector. +Enabled = false # Default +# CollectorTarget is the logical address of the OTEL Tracing Collector. +CollectorTarget = "localhost:4317" # Example +# NodeID is an unique name for this node relative to any other node traces are collected for. +NodeID = "NodeID" # Example +# SamplingRatio is the ratio of traces to sample for this node. +SamplingRatio = 1.0 # Example + +# Tracing.Attributes are user specified key-value pairs to associate in the context of the traces +[Tracing.Attributes] +# env is an example user specified key-value pair +env = "test" # Example diff --git a/core/config/docs/defaults.go b/core/config/docs/defaults.go index f0af4fe457c..8946d75cc65 100644 --- a/core/config/docs/defaults.go +++ b/core/config/docs/defaults.go @@ -23,5 +23,6 @@ func init() { func CoreDefaults() (c toml.Core) { c.SetFrom(&defaults) c.Database.Dialect = dialects.Postgres // not user visible - overridden for tests only + c.Tracing.Attributes = make(map[string]string) return } diff --git a/core/config/docs/docs.go b/core/config/docs/docs.go index c3b696e551f..df082465036 100644 --- a/core/config/docs/docs.go +++ b/core/config/docs/docs.go @@ -122,6 +122,24 @@ func newTable(line string, desc lines) *table { return t } +func newArrayOfTables(line string, desc lines) *table { + t := &table{ + name: strings.Trim(strings.Trim(line, fieldExample), "[]"), + codes: []string{line}, + desc: desc, + } + if len(desc) > 0 { + if strings.HasPrefix(strings.TrimSpace(desc[0]), tokenAdvanced) { + t.adv = true + t.desc = t.desc[1:] + } else if strings.HasPrefix(strings.TrimSpace(desc[len(desc)-1]), tokenExtended) { + t.ext = true + t.desc = t.desc[:len(desc)-1] + } + } + return t +} + func (t table) advanced() string { if t.adv { return advancedWarning("Do not change these settings unless you know what you are doing.") @@ -217,6 +235,10 @@ func parseTOMLDocs(s string) (items []fmt.Stringer, err error) { items = append(items, desc) desc = nil } + } else if strings.HasPrefix(line, "[[") { + currentTable = newArrayOfTables(line, desc) + items = append(items, currentTable) + desc = nil } else if strings.HasPrefix(line, "[") { currentTable = newTable(line, desc) items = append(items, currentTable) diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index f1a3ab1906c..276d0239941 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -1,7 +1,6 @@ package docs_test import ( - _ "embed" "strings" "testing" @@ -11,15 +10,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" + stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) @@ -37,6 +38,12 @@ func TestDoc(t *testing.T) { require.NoError(t, err) } + // Except for TelemetryIngress.ServerPubKey and TelemetryIngress.URL as this will be removed in the future + // and its only use is to signal to NOPs that these fields are no longer allowed + emptyString := "" + c.TelemetryIngress.ServerPubKey = &emptyString + c.TelemetryIngress.URL = new(models.URL) + cfgtest.AssertFieldsNotNil(t, c) var defaults chainlink.Config @@ -92,14 +99,14 @@ func TestDoc(t *testing.T) { }) t.Run("Solana", func(t *testing.T) { - var fallbackDefaults solana.SolanaConfig + var fallbackDefaults solana.TOMLConfig fallbackDefaults.SetDefaults() assertTOML(t, fallbackDefaults.Chain, defaults.Solana[0].Chain) }) t.Run("Starknet", func(t *testing.T) { - var fallbackDefaults starknet.StarknetConfig + var fallbackDefaults stkcfg.TOMLConfig fallbackDefaults.SetDefaults() assertTOML(t, fallbackDefaults.Chain, defaults.Starknet[0].Chain) diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go new file mode 100644 index 00000000000..59f4ed10dad --- /dev/null +++ b/core/config/mocks/telemetry_ingress.go @@ -0,0 +1,175 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + config "github.com/smartcontractkit/chainlink/v2/core/config" + mock "github.com/stretchr/testify/mock" + + time "time" + + url "net/url" +) + +// TelemetryIngress is an autogenerated mock type for the TelemetryIngress type +type TelemetryIngress struct { + mock.Mock +} + +// BufferSize provides a mock function with given fields: +func (_m *TelemetryIngress) BufferSize() uint { + ret := _m.Called() + + var r0 uint + if rf, ok := ret.Get(0).(func() uint); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint) + } + + return r0 +} + +// Endpoints provides a mock function with given fields: +func (_m *TelemetryIngress) Endpoints() []config.TelemetryIngressEndpoint { + ret := _m.Called() + + var r0 []config.TelemetryIngressEndpoint + if rf, ok := ret.Get(0).(func() []config.TelemetryIngressEndpoint); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]config.TelemetryIngressEndpoint) + } + } + + return r0 +} + +// Logging provides a mock function with given fields: +func (_m *TelemetryIngress) Logging() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// MaxBatchSize provides a mock function with given fields: +func (_m *TelemetryIngress) MaxBatchSize() uint { + ret := _m.Called() + + var r0 uint + if rf, ok := ret.Get(0).(func() uint); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint) + } + + return r0 +} + +// SendInterval provides a mock function with given fields: +func (_m *TelemetryIngress) SendInterval() time.Duration { + ret := _m.Called() + + var r0 time.Duration + if rf, ok := ret.Get(0).(func() time.Duration); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// SendTimeout provides a mock function with given fields: +func (_m *TelemetryIngress) SendTimeout() time.Duration { + ret := _m.Called() + + var r0 time.Duration + if rf, ok := ret.Get(0).(func() time.Duration); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Duration) + } + + return r0 +} + +// ServerPubKey provides a mock function with given fields: +func (_m *TelemetryIngress) ServerPubKey() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// URL provides a mock function with given fields: +func (_m *TelemetryIngress) URL() *url.URL { + ret := _m.Called() + + var r0 *url.URL + if rf, ok := ret.Get(0).(func() *url.URL); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*url.URL) + } + } + + return r0 +} + +// UniConn provides a mock function with given fields: +func (_m *TelemetryIngress) UniConn() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// UseBatchSend provides a mock function with given fields: +func (_m *TelemetryIngress) UseBatchSend() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// NewTelemetryIngress creates a new instance of TelemetryIngress. 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 NewTelemetryIngress(t interface { + mock.TestingT + Cleanup(func()) +}) *TelemetryIngress { + mock := &TelemetryIngress{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/config/mocks/telemetry_ingress_endpoint.go b/core/config/mocks/telemetry_ingress_endpoint.go new file mode 100644 index 00000000000..7aa6f46aa2b --- /dev/null +++ b/core/config/mocks/telemetry_ingress_endpoint.go @@ -0,0 +1,86 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package mocks + +import ( + url "net/url" + + mock "github.com/stretchr/testify/mock" +) + +// TelemetryIngressEndpoint is an autogenerated mock type for the TelemetryIngressEndpoint type +type TelemetryIngressEndpoint struct { + mock.Mock +} + +// ChainID provides a mock function with given fields: +func (_m *TelemetryIngressEndpoint) ChainID() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Network provides a mock function with given fields: +func (_m *TelemetryIngressEndpoint) Network() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ServerPubKey provides a mock function with given fields: +func (_m *TelemetryIngressEndpoint) ServerPubKey() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// URL provides a mock function with given fields: +func (_m *TelemetryIngressEndpoint) URL() *url.URL { + ret := _m.Called() + + var r0 *url.URL + if rf, ok := ret.Get(0).(func() *url.URL); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*url.URL) + } + } + + return r0 +} + +// NewTelemetryIngressEndpoint creates a new instance of TelemetryIngressEndpoint. 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 NewTelemetryIngressEndpoint(t interface { + mock.TestingT + Cleanup(func()) +}) *TelemetryIngressEndpoint { + mock := &TelemetryIngressEndpoint{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/config/telemetry_ingress_config.go b/core/config/telemetry_ingress_config.go index f784f996e07..f6c9fa3f858 100644 --- a/core/config/telemetry_ingress_config.go +++ b/core/config/telemetry_ingress_config.go @@ -5,14 +5,26 @@ import ( "time" ) +//go:generate mockery --quiet --name TelemetryIngress --output ./mocks/ --case=underscore --filename telemetry_ingress.go + type TelemetryIngress interface { Logging() bool UniConn() bool - ServerPubKey() string - URL() *url.URL BufferSize() uint MaxBatchSize() uint SendInterval() time.Duration SendTimeout() time.Duration UseBatchSend() bool + Endpoints() []TelemetryIngressEndpoint + + ServerPubKey() string // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions + URL() *url.URL // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions +} + +//go:generate mockery --quiet --name TelemetryIngressEndpoint --output ./mocks/ --case=underscore --filename telemetry_ingress_endpoint.go +type TelemetryIngressEndpoint interface { + Network() string + ChainID() string + ServerPubKey() string + URL() *url.URL } diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 5fba0c7ea5e..b7c8cfbc473 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -1,11 +1,11 @@ package toml import ( - _ "embed" "errors" "fmt" "net" "net/url" + "regexp" "strings" "github.com/google/uuid" @@ -52,6 +52,7 @@ type Core struct { Pyroscope Pyroscope `toml:",omitempty"` Sentry Sentry `toml:",omitempty"` Insecure Insecure `toml:",omitempty"` + Tracing Tracing `toml:",omitempty"` } // SetFrom updates c with any non-nil values from f. (currently TOML field only!) @@ -85,6 +86,7 @@ func (c *Core) SetFrom(f *Core) { c.Pyroscope.setFrom(&f.Pyroscope) c.Sentry.setFrom(&f.Sentry) c.Insecure.setFrom(&f.Insecure) + c.Tracing.setFrom(&f.Tracing) } func (c *Core) ValidateConfig() (err error) { @@ -141,9 +143,13 @@ func validateDBURL(dbURI url.URL) error { } func (d *DatabaseSecrets) ValidateConfig() (err error) { + return d.validateConfig(build.Mode()) +} + +func (d *DatabaseSecrets) validateConfig(buildMode string) (err error) { if d.URL == nil || (*url.URL)(d.URL).String() == "" { err = multierr.Append(err, configutils.ErrEmpty{Name: "URL", Msg: "must be provided and non-empty"}) - } else if *d.AllowSimplePasswords && build.IsProd() { + } else if *d.AllowSimplePasswords && buildMode == build.Prod { err = multierr.Append(err, configutils.ErrInvalid{Name: "AllowSimplePasswords", Value: true, Msg: "insecure configs are not allowed on secure builds"}) } else if !*d.AllowSimplePasswords { if verr := validateDBURL((url.URL)(*d.URL)); verr != nil { @@ -422,13 +428,22 @@ func (d *DatabaseBackup) setFrom(f *DatabaseBackup) { type TelemetryIngress struct { UniConn *bool Logging *bool - ServerPubKey *string - URL *models.URL BufferSize *uint16 MaxBatchSize *uint16 SendInterval *models.Duration SendTimeout *models.Duration UseBatchSend *bool + Endpoints []TelemetryIngressEndpoint `toml:",omitempty"` + + URL *models.URL `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions + ServerPubKey *string `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions +} + +type TelemetryIngressEndpoint struct { + Network *string + ChainID *string + URL *models.URL + ServerPubKey *string } func (t *TelemetryIngress) setFrom(f *TelemetryIngress) { @@ -438,12 +453,6 @@ func (t *TelemetryIngress) setFrom(f *TelemetryIngress) { if v := f.Logging; v != nil { t.Logging = v } - if v := f.ServerPubKey; v != nil { - t.ServerPubKey = v - } - if v := f.URL; v != nil { - t.URL = v - } if v := f.BufferSize; v != nil { t.BufferSize = v } @@ -459,6 +468,29 @@ func (t *TelemetryIngress) setFrom(f *TelemetryIngress) { if v := f.UseBatchSend; v != nil { t.UseBatchSend = v } + if v := f.Endpoints; v != nil { + t.Endpoints = v + } + if v := f.ServerPubKey; v != nil { + t.ServerPubKey = v + } + if v := f.URL; v != nil { + t.URL = v + } +} + +func (t *TelemetryIngress) ValidateConfig() (err error) { + if (!t.URL.IsZero() || *t.ServerPubKey != "") && len(t.Endpoints) > 0 { + return configutils.ErrInvalid{Name: "URL", Value: t.URL.String(), + Msg: `Cannot set both TelemetryIngress.URL and TelemetryIngress.ServerPubKey alongside TelemetryIngress.Endpoints. Please use only TelemetryIngress.Endpoints: + [[TelemetryIngress.Endpoints]] + Network = '...' # e.g. EVM. Solana, Starknet, Cosmos + ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta + URL = '...' + ServerPubKey = '...'`} + } + + return nil } type AuditLogger struct { @@ -1142,14 +1174,18 @@ type Insecure struct { } func (ins *Insecure) ValidateConfig() (err error) { - if build.IsDev() { + return ins.validateConfig(build.Mode()) +} + +func (ins *Insecure) validateConfig(buildMode string) (err error) { + if buildMode == build.Dev { return } if ins.DevWebServer != nil && *ins.DevWebServer { err = multierr.Append(err, configutils.ErrInvalid{Name: "DevWebServer", Value: *ins.DevWebServer, Msg: "insecure configs are not allowed on secure builds"}) } - // OCRDevelopmentMode is allowed on test builds. - if ins.OCRDevelopmentMode != nil && *ins.OCRDevelopmentMode && !build.IsTest() { + // OCRDevelopmentMode is allowed on dev/test builds. + if ins.OCRDevelopmentMode != nil && *ins.OCRDevelopmentMode && buildMode == build.Prod { err = multierr.Append(err, configutils.ErrInvalid{Name: "OCRDevelopmentMode", Value: *ins.OCRDevelopmentMode, Msg: "insecure configs are not allowed on secure builds"}) } if ins.InfiniteDepthQueries != nil && *ins.InfiniteDepthQueries { @@ -1267,3 +1303,84 @@ func (t *ThresholdKeyShareSecrets) validateMerge(f *ThresholdKeyShareSecrets) (e return err } + +type Tracing struct { + Enabled *bool + CollectorTarget *string + NodeID *string + SamplingRatio *float64 + Attributes map[string]string `toml:",omitempty"` +} + +func (t *Tracing) setFrom(f *Tracing) { + if v := f.Enabled; v != nil { + t.Enabled = f.Enabled + } + if v := f.CollectorTarget; v != nil { + t.CollectorTarget = f.CollectorTarget + } + if v := f.NodeID; v != nil { + t.NodeID = f.NodeID + } + if v := f.Attributes; v != nil { + t.Attributes = f.Attributes + } + if v := f.SamplingRatio; v != nil { + t.SamplingRatio = f.SamplingRatio + } +} + +func (t *Tracing) ValidateConfig() (err error) { + if t.Enabled == nil || !*t.Enabled { + return err + } + + if t.SamplingRatio != nil { + if *t.SamplingRatio < 0 || *t.SamplingRatio > 1 { + err = multierr.Append(err, configutils.ErrInvalid{Name: "SamplingRatio", Value: *t.SamplingRatio, Msg: "must be between 0 and 1"}) + } + } + + if t.CollectorTarget != nil { + ok := isValidURI(*t.CollectorTarget) + if !ok { + err = multierr.Append(err, configutils.ErrInvalid{Name: "CollectorTarget", Value: *t.CollectorTarget, Msg: "must be a valid URI"}) + } + } + + return err +} + +var hostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*$`) + +func isValidURI(uri string) bool { + if strings.Contains(uri, "://") { + // Standard URI check + _, _ = url.ParseRequestURI(uri) + // TODO: BCF-2703. Handle error. All external addresses currently fail validation until we have secure transport to external networks. + return false + } + + // For URIs like "otel-collector:4317" + parts := strings.Split(uri, ":") + if len(parts) == 2 { + host, port := parts[0], parts[1] + + // Validating hostname + if !isValidHostname(host) { + return false + } + + // Validating port + if _, err := net.LookupPort("tcp", port); err != nil { + return false + } + + return true + } + return false +} + +func isValidHostname(hostname string) bool { + return hostnameRegex.MatchString(hostname) +} diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index 2ab3f0fb86b..92aaa024304 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" + configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) func TestMercurySecrets_valid(t *testing.T) { @@ -107,7 +108,7 @@ func Test_validateDBURL(t *testing.T) { } } -func TestValidateConfig(t *testing.T) { +func TestDatabaseSecrets_ValidateConfig(t *testing.T) { validUrl := models.URL(url.URL{Scheme: "https", Host: "localhost"}) validSecretURL := *models.NewSecretURL(&validUrl) @@ -120,7 +121,7 @@ func TestValidateConfig(t *testing.T) { tests := []struct { name string input *DatabaseSecrets - skip bool + buildMode string expectedErrContains []string }{ { @@ -143,7 +144,7 @@ func TestValidateConfig(t *testing.T) { URL: &validSecretURL, AllowSimplePasswords: &[]bool{true}[0], }, - skip: !build.IsProd(), + buildMode: build.Prod, expectedErrContains: []string{"insecure configs are not allowed on secure builds"}, }, { @@ -159,11 +160,11 @@ func TestValidateConfig(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // needed while -tags test is supported - if tt.skip { - t.SkipNow() + buildMode := build.Mode() + if tt.buildMode != "" { + buildMode = tt.buildMode } - err := tt.input.ValidateConfig() + err := tt.input.validateConfig(buildMode) if err == nil && len(tt.expectedErrContains) > 0 { t.Errorf("expected errors but got none") return @@ -180,3 +181,133 @@ func TestValidateConfig(t *testing.T) { }) } } +func TestTracing_ValidateCollectorTarget(t *testing.T) { + tests := []struct { + name string + collectorTarget *string + wantErr bool + errMsg string + }{ + { + name: "valid http address", + collectorTarget: ptr("https://localhost:4317"), + // TODO: BCF-2703. Re-enable when we have secure transport to otel collectors in external networks + wantErr: true, + errMsg: "CollectorTarget: invalid value (https://localhost:4317): must be a valid URI", + }, + { + name: "valid localhost address", + collectorTarget: ptr("localhost:4317"), + wantErr: false, + }, + { + name: "valid docker address", + collectorTarget: ptr("otel-collector:4317"), + wantErr: false, + }, + { + name: "valid IP address", + collectorTarget: ptr("192.168.1.1:4317"), + wantErr: false, + }, + { + name: "invalid port", + collectorTarget: ptr("localhost:invalid"), + wantErr: true, + errMsg: "CollectorTarget: invalid value (localhost:invalid): must be a valid URI", + }, + { + name: "invalid address", + collectorTarget: ptr("invalid address"), + wantErr: true, + errMsg: "CollectorTarget: invalid value (invalid address): must be a valid URI", + }, + { + name: "nil CollectorTarget", + collectorTarget: ptr(""), + wantErr: true, + errMsg: "CollectorTarget: invalid value (): must be a valid URI", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tracing := &Tracing{ + Enabled: ptr(true), + CollectorTarget: tt.collectorTarget, + } + + err := tracing.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestTracing_ValidateSamplingRatio(t *testing.T) { + tests := []struct { + name string + samplingRatio *float64 + wantErr bool + errMsg string + }{ + { + name: "valid lower bound", + samplingRatio: ptr(0.0), + wantErr: false, + }, + { + name: "valid upper bound", + samplingRatio: ptr(1.0), + wantErr: false, + }, + { + name: "valid value", + samplingRatio: ptr(0.5), + wantErr: false, + }, + { + name: "invalid negative value", + samplingRatio: ptr(-0.1), + wantErr: true, + errMsg: configutils.ErrInvalid{Name: "SamplingRatio", Value: -0.1, Msg: "must be between 0 and 1"}.Error(), + }, + { + name: "invalid value greater than 1", + samplingRatio: ptr(1.1), + wantErr: true, + errMsg: configutils.ErrInvalid{Name: "SamplingRatio", Value: 1.1, Msg: "must be between 0 and 1"}.Error(), + }, + { + name: "nil SamplingRatio", + samplingRatio: nil, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tracing := Tracing{ + SamplingRatio: tt.samplingRatio, + Enabled: ptr(true), + } + + err := tracing.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + +// ptr is a utility function for converting a value to a pointer to the value. +func ptr[T any](t T) *T { return &t } diff --git a/core/config/tracing_config.go b/core/config/tracing_config.go new file mode 100644 index 00000000000..28584a9cde4 --- /dev/null +++ b/core/config/tracing_config.go @@ -0,0 +1,9 @@ +package config + +type Tracing interface { + Enabled() bool + CollectorTarget() string + NodeID() string + Attributes() map[string]string + SamplingRatio() float64 +} diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 94f1efd2d6a..32db52a029f 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -35,10 +35,11 @@ type FunctionsBillingConfig struct { FeedStalenessSeconds uint32 GasOverheadBeforeCallback uint32 GasOverheadAfterCallback uint32 - RequestTimeoutSeconds uint32 DonFee *big.Int + MinimumEstimateGasPriceWei *big.Int MaxSupportedRequestDataVersion uint16 FallbackNativePerUnitLink *big.Int + RequestTimeoutSeconds uint32 } type FunctionsResponseCommitment struct { @@ -70,8 +71,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b50604051620050f4380380620050f4833981016040819052620000349162000418565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b505050505050620005c6565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f56200033b565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160e81b0261ffff60e81b196001600160481b03909216600160a01b02600160a01b600160e81b031963ffffffff948516600160801b0216600160801b600160e81b03199585166c010000000000000000000000000263ffffffff60601b19978616680100000000000000000297909716600160401b600160801b0319998616640100000000026001600160401b0319909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980546001600160e01b039092166001600160e01b0319909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a906200033090839062000536565b60405180910390a150565b6200034562000347565b565b6000546001600160a01b03163314620003455760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003bb57600080fd5b919050565b805163ffffffff81168114620003bb57600080fd5b80516001600160481b0381168114620003bb57600080fd5b805161ffff81168114620003bb57600080fd5b80516001600160e01b0381168114620003bb57600080fd5b60008060008385036101408112156200043057600080fd5b6200043b85620003a3565b935061010080601f19830112156200045257600080fd5b60405191508082016001600160401b03811183821017156200048457634e487b7160e01b600052604160045260246000fd5b6040526200049560208701620003c0565b8252620004a560408701620003c0565b6020830152620004b860608701620003c0565b6040830152620004cb60808701620003c0565b6060830152620004de60a08701620003c0565b6080830152620004f160c08701620003d5565b60a08301526200050460e08701620003ed565b60c08301526200051681870162000400565b60e08301525091506200052d6101208501620003a3565b90509250925092565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525060018060481b0360a08401511660a083015260c0830151620005a360c084018261ffff169052565b5060e0830151620005bf60e08401826001600160e01b03169052565b5092915050565b60805160a051614ade62000616600039600081816105be0152818161074c01528181610a1f01528181610cb301528181610ffa015281816117e50152613235015260006112230152614ade6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806385b214cf116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610529578063e4ddcea61461053c578063f2fde38b1461055257600080fd5b8063c3f909d4146103b4578063d227d245146104f1578063d328a91e1461052157600080fd5b8063a631571e116100bd578063a631571e14610361578063afcb95d714610381578063b1dc65a4146103a157600080fd5b806385b214cf146103135780638da5cb5b146103265780639314176d1461034e57600080fd5b806379ba509711610145578063814118341161011f578063814118341461028957806381f1b9381461029e57806381ff7048146102a657600080fd5b806379ba5097146102665780637d4807871461026e5780637f15e1661461027657600080fd5b80632a905ccc116101765780632a905ccc146101f957806359b5b7ac1461021b57806366316d8d1461025357600080fd5b8063083a546614610192578063181f5a77146101a7575b600080fd5b6101a56101a0366004613528565b610565565b005b6101e36040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e302e300000000081525081565b6040516101f091906135ce565b60405180910390f35b6102016105ba565b60405168ffffffffffffffffff90911681526020016101f0565b61020161022936600461371e565b5060085474010000000000000000000000000000000000000000900468ffffffffffffffffff1690565b6101a56102613660046137ad565b610650565b6101a5610809565b6101a561090b565b6101a5610284366004613528565b610b0b565b610291610b5b565b6040516101f09190613837565b6101e3610bca565b6102f060015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff9485168152939092166020840152908201526060016101f0565b6101a561032136600461384a565b610c9b565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b6101a561035c3660046138e0565b610d58565b61037461036f3660046139aa565b610f89565b6040516101f09190613aff565b6040805160018152600060208201819052918101919091526060016101f0565b6101a56103af366004613b53565b61112a565b6104e46040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915250604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a08201527d01000000000000000000000000000000000000000000000000000000000090910461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e082015290565b6040516101f09190613c0a565b6105046104ff366004613cca565b6117e1565b6040516bffffffffffffffffffffffff90911681526020016101f0565b6101e3611943565b6101a5610537366004613de3565b61199a565b6105446123c6565b6040519081526020016101f0565b6101a5610560366004613eb0565b6125eb565b61056d6125ff565b60008190036105a8576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105b5828483613f66565b505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064b919061408c565b905090565b610658612682565b806bffffffffffffffffffffffff166000036106925750336000908152600a60205260409020546bffffffffffffffffffffffff166106ec565b336000908152600a60205260409020546bffffffffffffffffffffffff808316911610156106ec576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906107199084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061076e7f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b1580156107ed57600080fd5b505af1158015610801573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61091361282d565b61091b612682565b6000610925610b5b565b905060005b8151811015610b07576000600a600084848151811061094b5761094b6140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610af6576000600a60008585815181106109aa576109aa6140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610a417f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610a6e57610a6e6140fd565b6020026020010151836040518363ffffffff1660e01b8152600401610ac392919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610add57600080fd5b505af1158015610af1573d6000803e3d6000fd5b505050505b50610b008161412c565b905061092a565b5050565b610b136125ff565b6000819003610b4e576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105b5828483613f66565b60606006805480602002602001604051908101604052809291908181526020018280548015610bc057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b95575b5050505050905090565b6060600d8054610bd990613ecd565b9050600003610c14576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610c2190613ecd565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4d90613ecd565b8015610bc05780601f10610c6f57610100808354040283529160200191610bc0565b820191906000526020600020905b815481529060010190602001808311610c7d57509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610d0a576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f41690610d4d9083815260200190565b60405180910390a150565b610d6061282d565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167d010000000000000000000000000000000000000000000000000000000000027fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90921674010000000000000000000000000000000000000000027fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff63ffffffff94851670010000000000000000000000000000000002167fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff9585166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9786166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b1695909c1694909417989098179690961698909817929092171617929092179390931692909217905560e0820151600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092167fffffffff00000000000000000000000000000000000000000000000000000000909216919091179055517f8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a90610d4d908390613c0a565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611051576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61106261105d83614164565b612835565b90506110746060830160408401613eb0565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff326110c260c0870160a08801614251565b6110d461016088016101408901613eb0565b6110de888061426e565b6110f06101208b016101008c016142d3565b60208b01356111066101008d0160e08e016142ee565b8b60405161111c9998979695949392919061430b565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff80821660208501526101009091041692820192909252908314611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610886565b61121f8b8b8b8b8b8b612c36565b60007f00000000000000000000000000000000000000000000000000000000000000001561127c5760028260200151836040015161125d91906143b3565b61126791906143fb565b6112729060016143b3565b60ff169050611292565b602082015161128c9060016143b3565b60ff1690505b8881146112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610886565b888714611364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610886565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113a7576113a761441d565b60028111156113b8576113b861441d565b90525090506002816020015160028111156113d5576113d561441d565b14801561141c57506006816000015160ff16815481106113f7576113f76140fd565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610886565b505050505061148f6134c0565b6000808a8a6040516114a292919061444c565b6040519081900381206114b9918e9060200161445c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117c3576000600184898460208110611522576115226140fd565b61152f91901a601b6143b3565b8e8e86818110611541576115416140fd565b905060200201358d8d8781811061155a5761155a6140fd565b9050602002013560405160008152602001604052604051611597949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156115b9573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156116395761163961441d565b600281111561164a5761164a61441d565b90525092506001836020015160028111156116675761166761441d565b146116ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610886565b8251600090879060ff16601f81106116e8576116e86140fd565b602002015173ffffffffffffffffffffffffffffffffffffffff161461176a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610886565b8086846000015160ff16601f8110611784576117846140fd565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117af6001866143b3565b945050806117bc9061412c565b9050611503565b5050506117d4833383858e8e612ced565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561188157600080fd5b505afa158015611895573d6000803e3d6000fd5b5050505066038d7ea4c680008211156118da576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118e46105ba565b9050600061192787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061022992505050565b905061193585858385612ebb565b925050505b95945050505050565b6060600c805461195290613ecd565b905060000361198d576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610c2190613ecd565b855185518560ff16601f831115611a0d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610886565b80600003611a77576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610886565b818314611b05576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610886565b611b10816003614470565b8311611b78576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610886565b611b806125ff565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611bc79088612fa5565b60055415611d7c57600554600090611be190600190614487565b9050600060058281548110611bf857611bf86140fd565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c3257611c326140fd565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cb257611cb261449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d1b57611d1b61449a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611bc7915050565b60005b8151518110156121e35760006004600084600001518481518110611da557611da56140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611def57611def61441d565b14611e56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610886565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611e8757611e876140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f2857611f2861441d565b021790555060009150611f389050565b6004600084602001518481518110611f5257611f526140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611f9c57611f9c61441d565b14612003576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610886565b6040805180820190915260ff821681526020810160028152506004600084602001518481518110612036576120366140fd565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156120d7576120d761441d565b0217905550508251805160059250839081106120f5576120f56140fd565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9093169290921790915582015180516006919083908110612171576121716140fd565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806121db8161412c565b915050611d7f565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161229b918491740100000000000000000000000000000000000000009004166144c9565b92506101000a81548163ffffffff021916908363ffffffff1602179055506122fa4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151612fbe565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123b1988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926144e6565b60405180910390a15050505050505050505050565b604080516101008101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c01000000000000000000000000808304821660608501527001000000000000000000000000000000008304909116608084015274010000000000000000000000000000000000000000820468ffffffffffffffffff1660a0808501919091527d01000000000000000000000000000000000000000000000000000000000090920461ffff1660c08401526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612520573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125449190614596565b5093505092505080426125579190614487565b836020015163ffffffff1610801561257957506000836020015163ffffffff16115b156125a757505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b600082136125e4576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610886565b5092915050565b6125f36125ff565b6125fc81613069565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314612680576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610886565b565b600b546bffffffffffffffffffffffff1660000361269c57565b60006126a6610b5b565b905080516000036126e3576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612702916bffffffffffffffffffffffff166145e6565b905060005b82518110156127ce5781600a6000858481518110612727576127276140fd565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff1661278f9190614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806127c79061412c565b9050612707565b5081516127db9082614636565b600b80546000906127fb9084906bffffffffffffffffffffffff166140d8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6126806125ff565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915260408051610100808201835260085463ffffffff80821684526401000000008204811660208501526801000000000000000082048116948401949094526c010000000000000000000000008104841660608401527001000000000000000000000000000000008104909316608083015274010000000000000000000000000000000000000000830468ffffffffffffffffff1660a08301527d01000000000000000000000000000000000000000000000000000000000090920461ffff90811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660e0840152928501519192911611156129bb576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460009074010000000000000000000000000000000000000000900468ffffffffffffffffff16905060006129fc8560e001513a848860800151612ebb565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612a58576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612adb3087604001518860a001518960c001516001612a799190614666565b6040805173ffffffffffffffffffffffffffffffffffffffff958616602080830191909152949095168582015267ffffffffffffffff928316606086015291166080808501919091528151808503909101815260a09093019052815191012090565b90506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff168152602001876040015173ffffffffffffffffffffffffffffffffffffffff1681526020018760a0015167ffffffffffffffff1681526020018760e0015163ffffffff168152602001876080015168ffffffffffffffffff1681526020018468ffffffffffffffffff168152602001856040015163ffffffff1664ffffffffff168152602001856060015163ffffffff1664ffffffffff168152602001856080015163ffffffff1642612bcd9190614687565b63ffffffff16815250945084604051602001612be99190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600093845260079092529091205550919392505050565b6000612c43826020614470565b612c4e856020614470565b612c5a88610144614687565b612c649190614687565b612c6e9190614687565b612c79906000614687565b9050368114612ce4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610886565b50505050505050565b606080808080612cff86880188614775565b8451949950929750909550935091501580612d1c57508351855114155b80612d2957508251855114155b80612d3657508151855114155b80612d4357508051855114155b15612d7a576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612ead576000612e12878381518110612d9d57612d9d6140fd565b6020026020010151878481518110612db757612db76140fd565b6020026020010151878581518110612dd157612dd16140fd565b6020026020010151878681518110612deb57612deb6140fd565b6020026020010151878781518110612e0557612e056140fd565b602002602001015161315e565b90506000816006811115612e2857612e2861441d565b1480612e4557506001816006811115612e4357612e4361441d565b145b15612e9c57868281518110612e5c57612e5c6140fd565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612ea68161412c565b9050612d7d565b505050505050505050505050565b60085460009081908690612ef39063ffffffff6c010000000000000000000000008204811691680100000000000000009004166144c9565b612efd91906144c9565b60085463ffffffff918216925060009161271091612f1c911688614470565b612f269190614847565b612f309087614687565b90506000612f3d826133ef565b90506000612f59846bffffffffffffffffffffffff8416614470565b90506000612f7568ffffffffffffffffff808916908a16614611565b9050612f97612f926bffffffffffffffffffffffff831684614687565b61341e565b9a9950505050505050505050565b6000612faf610b5b565b511115610b0757610b07612682565b6000808a8a8a8a8a8a8a8a8a604051602001612fe29998979695949392919061485b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036130e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610886565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906131759190614931565b60008881526007602052604090205490915061319557600291505061193a565b806040516020016131a69190613aff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060008a81526007909352912054146131f857600691505061193a565b60006132033a6133ef565b9050600082610120015183610100015161321d9190614a04565b61322e9064ffffffffff1683614636565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff168861328d9190614611565b338b6040518763ffffffff1660e01b81526004016132b096959493929190614a22565b60408051808303816000875af11580156132ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f29190614a9e565b9092509050600082600681111561330b5761330b61441d565b1480613328575060018260068111156133265761332661441d565b145b156133e15760008b8152600760205260408120556133468184614611565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff909216939092916133b291859116614611565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b60006134186133fc6123c6565b61340e84670de0b6b3a7640000614470565b612f929190614847565b92915050565b60006bffffffffffffffffffffffff8211156134bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610886565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126134f157600080fd5b50813567ffffffffffffffff81111561350957600080fd5b60208301915083602082850101111561352157600080fd5b9250929050565b6000806020838503121561353b57600080fd5b823567ffffffffffffffff81111561355257600080fd5b61355e858286016134df565b90969095509350505050565b6000815180845260005b8181101561359057602081850181015186830182015201613574565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006135e1602083018461356a565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561363b5761363b6135e8565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613688576136886135e8565b604052919050565b600082601f8301126136a157600080fd5b813567ffffffffffffffff8111156136bb576136bb6135e8565b6136ec60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613641565b81815284602083860101111561370157600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561373057600080fd5b813567ffffffffffffffff81111561374757600080fd5b61375384828501613690565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146125fc57600080fd5b80356111258161375b565b6bffffffffffffffffffffffff811681146125fc57600080fd5b803561112581613788565b600080604083850312156137c057600080fd5b82356137cb8161375b565b915060208301356137db81613788565b809150509250929050565b600081518084526020808501945080840160005b8381101561382c57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016137fa565b509495945050505050565b6020815260006135e160208301846137e6565b60006020828403121561385c57600080fd5b5035919050565b63ffffffff811681146125fc57600080fd5b803561112581613863565b68ffffffffffffffffff811681146125fc57600080fd5b803561112581613880565b803561ffff8116811461112557600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461112557600080fd5b60006101008083850312156138f457600080fd5b6040519081019067ffffffffffffffff82118183101715613917576139176135e8565b816040528335915061392882613863565b81815261393760208501613875565b602082015261394860408501613875565b604082015261395960608501613875565b606082015261396a60808501613875565b608082015261397b60a08501613897565b60a082015261398c60c085016138a2565b60c082015261399d60e085016138b4565b60e0820152949350505050565b6000602082840312156139bc57600080fd5b813567ffffffffffffffff8111156139d357600080fd5b820161016081850312156135e157600080fd5b805182526020810151613a11602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613a3160408401826bffffffffffffffffffffffff169052565b506060810151613a59606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613a75608084018267ffffffffffffffff169052565b5060a0810151613a8d60a084018263ffffffff169052565b5060c0810151613aaa60c084018268ffffffffffffffffff169052565b5060e0810151613ac760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161341882846139e6565b60008083601f840112613b2057600080fd5b50813567ffffffffffffffff811115613b3857600080fd5b6020830191508360208260051b850101111561352157600080fd5b60008060008060008060008060e0898b031215613b6f57600080fd5b606089018a811115613b8057600080fd5b8998503567ffffffffffffffff80821115613b9a57600080fd5b613ba68c838d016134df565b909950975060808b0135915080821115613bbf57600080fd5b613bcb8c838d01613b0e565b909750955060a08b0135915080821115613be457600080fd5b50613bf18b828c01613b0e565b999c989b50969995989497949560c00135949350505050565b60006101008201905063ffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401525068ffffffffffffffffff60a08401511660a083015260c0830151613c7960c084018261ffff169052565b5060e08301516125e460e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b67ffffffffffffffff811681146125fc57600080fd5b803561112581613ca9565b600080600080600060808688031215613ce257600080fd5b8535613ced81613ca9565b9450602086013567ffffffffffffffff811115613d0957600080fd5b613d15888289016134df565b9095509350506040860135613d2981613863565b949793965091946060013592915050565b600067ffffffffffffffff821115613d5457613d546135e8565b5060051b60200190565b600082601f830112613d6f57600080fd5b81356020613d84613d7f83613d3a565b613641565b82815260059290921b84018101918181019086841115613da357600080fd5b8286015b84811015613dc7578035613dba8161375b565b8352918301918301613da7565b509695505050505050565b803560ff8116811461112557600080fd5b60008060008060008060c08789031215613dfc57600080fd5b863567ffffffffffffffff80821115613e1457600080fd5b613e208a838b01613d5e565b97506020890135915080821115613e3657600080fd5b613e428a838b01613d5e565b9650613e5060408a01613dd2565b95506060890135915080821115613e6657600080fd5b613e728a838b01613690565b9450613e8060808a01613cbf565b935060a0890135915080821115613e9657600080fd5b50613ea389828a01613690565b9150509295509295509295565b600060208284031215613ec257600080fd5b81356135e18161375b565b600181811c90821680613ee157607f821691505b602082108103613f1a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105b557600081815260208120601f850160051c81016020861015613f475750805b601f850160051c820191505b8181101561080157828155600101613f53565b67ffffffffffffffff831115613f7e57613f7e6135e8565b613f9283613f8c8354613ecd565b83613f20565b6000601f841160018114613fe45760008515613fae5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561407a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140335786850135825560209485019460019092019101614013565b508682101561406e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161112581613880565b60006020828403121561409e57600080fd5b81516135e181613880565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8281168282160390808211156125e4576125e46140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361415d5761415d6140a9565b5060010190565b6000610160823603121561417757600080fd5b61417f613617565b823567ffffffffffffffff81111561419657600080fd5b6141a236828601613690565b825250602083013560208201526141bb6040840161377d565b60408201526141cc606084016137a2565b60608201526141dd60808401613897565b60808201526141ee60a08401613cbf565b60a08201526141ff60c08401613cbf565b60c082015261421060e08401613875565b60e08201526101006142238185016138a2565b90820152610120614235848201613cbf565b9082015261014061424784820161377d565b9082015292915050565b60006020828403121561426357600080fd5b81356135e181613ca9565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126142a357600080fd5b83018035915067ffffffffffffffff8211156142be57600080fd5b60200191503681900382131561352157600080fd5b6000602082840312156142e557600080fd5b6135e1826138a2565b60006020828403121561430057600080fd5b81356135e181613863565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168301019050612f9760e08301846139e6565b60ff8181168382160190811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061440e5761440e6143cc565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613418576134186140a9565b81810381811115613418576134186140a9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff8181168382160190808211156125e4576125e46140a9565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526145168184018a6137e6565b9050828103608084015261452a81896137e6565b905060ff871660a084015282810360c0840152614547818761356a565b905067ffffffffffffffff851660e084015282810361010084015261456c818561356a565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461112557600080fd5b600080600080600060a086880312156145ae57600080fd5b6145b78661457c565b94506020860151935060408601519250606086015191506145da6080870161457c565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614605576146056143cc565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160190808211156125e4576125e46140a9565b6bffffffffffffffffffffffff81811683821602808216919082811461465e5761465e6140a9565b505092915050565b67ffffffffffffffff8181168382160190808211156125e4576125e46140a9565b80820180821115613418576134186140a9565b600082601f8301126146ab57600080fd5b813560206146bb613d7f83613d3a565b82815260059290921b840181019181810190868411156146da57600080fd5b8286015b84811015613dc757803583529183019183016146de565b600082601f83011261470657600080fd5b81356020614716613d7f83613d3a565b82815260059290921b8401810191818101908684111561473557600080fd5b8286015b84811015613dc757803567ffffffffffffffff8111156147595760008081fd5b6147678986838b0101613690565b845250918301918301614739565b600080600080600060a0868803121561478d57600080fd5b853567ffffffffffffffff808211156147a557600080fd5b6147b189838a0161469a565b965060208801359150808211156147c757600080fd5b6147d389838a016146f5565b955060408801359150808211156147e957600080fd5b6147f589838a016146f5565b9450606088013591508082111561480b57600080fd5b61481789838a016146f5565b9350608088013591508082111561482d57600080fd5b5061483a888289016146f5565b9150509295509295909350565b600082614856576148566143cc565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526148a28285018b6137e6565b915083820360808501526148b6828a6137e6565b915060ff881660a085015283820360c08501526148d3828861356a565b90861660e0850152838103610100850152905061456c818561356a565b80516111258161375b565b805161112581613788565b805161112581613ca9565b805161112581613863565b805164ffffffffff8116811461112557600080fd5b6000610160828403121561494457600080fd5b61494c613617565b8251815261495c602084016148f0565b602082015261496d604084016148fb565b604082015261497e606084016148f0565b606082015261498f60808401614906565b60808201526149a060a08401614911565b60a08201526149b160c08401614081565b60c08201526149c260e08401614081565b60e08201526101006149d581850161491c565b908201526101206149e784820161491c565b908201526101406149f9848201614911565b908201529392505050565b64ffffffffff8181168382160190808211156125e4576125e46140a9565b6000610200808352614a368184018a61356a565b90508281036020840152614a4a818961356a565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614a93905060a08301846139e6565b979650505050505050565b60008060408385031215614ab157600080fd5b825160078110614ac057600080fd5b60208401519092506137db8161378856fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b506040516200529938038062005299833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614c166200068360003960008181610845015281816109d301528181610ca601528181610f3a0152818161104501528181611830015261332c0152600061126e0152614c166000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a036600461361f565b61059c565b005b6101a56101b53660046137c8565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b60405161020391906138e2565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c36600461398a565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613a19565b6108d7565b6101a5610a90565b6101a5610b92565b6101a561029336600461361f565b610d92565b6102a0610de2565b6040516102039190613aa3565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613ab6565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613acf565b610fd4565b6040516102039190613c24565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613c78565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b6040516102039190613d2f565b61053b610536366004613e1f565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004613f38565b6119e3565b61057b61240f565b604051908152602001610203565b6101a5610597366004614005565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec8284836140bb565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f518486290610836908390613d2f565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906141e1565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661422d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614252565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614252565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614281565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec8284836140bb565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614022565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614022565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614022565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a8836142b9565b6128b2565b90506110bf6060830160408401614005565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a088016143a6565b61111f61016088016101408901614005565b61112988806143c3565b61113b6101208b016101008c01614428565b60208b01356111516101008d0160e08e01614443565b8b60405161116799989796959493929190614460565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a89190614508565b6112b29190614550565b6112bd906001614508565b60ff1690506112dd565b60208201516112d7906001614508565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614572565b600281111561140357611403614572565b905250905060028160200151600281111561142057611420614572565b14801561146757506006816000015160ff168154811061144257611442614252565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da6135b7565b6000808a8a6040516114ed9291906145a1565b604051908190038120611504918e906020016145b1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614252565b61157a91901a601b614508565b8e8e8681811061158c5761158c614252565b905060200201358d8d878181106115a5576115a5614252565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614572565b600281111561169557611695614572565b90525092506001836020015160028111156116b2576116b2614572565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614252565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614252565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa600186614508565b9450508061180790614281565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd5565b98975050505050505050565b6060600c805461199b90614022565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614022565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036145c5565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c10908861311d565b60055415611dc557600554600090611c2a906001906145dc565b9050600060058281548110611c4157611c41614252565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614252565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6145ef565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646145ef565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614572565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614572565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614572565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614572565b02179055505082518051600592508390811061213e5761213e614252565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614252565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614281565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e49184917401000000000000000000000000000000000000000090041661461e565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613136565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261463b565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906146eb565b5093505092505080426125d491906145dc565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b612679816131e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff1661473b565b905060005b82518110156128535781600a60008584815181106127ac576127ac614252565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128149190614766565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c90614281565b905061278c565b508151612860908261478b565b600b80546000906128809084906bffffffffffffffffffffffff1661422d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd5565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f91906147b3565b905060003087604001518860a001518960c001516001612b3f91906147c6565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613c24565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d8260206145c5565b612d688560206145c5565b612d74886101446147b3565b612d7e91906147b3565b612d8891906147b3565b612d939060006147b3565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e19868801886148c2565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc7576000612f2c878381518110612eb757612eb7614252565b6020026020010151878481518110612ed157612ed1614252565b6020026020010151878581518110612eeb57612eeb614252565b6020026020010151878681518110612f0557612f05614252565b6020026020010151878781518110612f1f57612f1f614252565b60200260200101516132d6565b90506000816006811115612f4257612f42614572565b1480612f5f57506001816006811115612f5d57612f5d614572565b145b15612fb657868281518110612f7657612f76614252565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc081614281565b9050612e97565b505050505050505050505050565b6008546000908190869061300d9063ffffffff6c0100000000000000000000000082048116916801000000000000000090041661461e565b613017919061461e565b60085463ffffffff919091169150790100000000000000000000000000000000000000000000000000900464ffffffffff1685101561307a57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1694505b600854600090612710906130949063ffffffff16886145c5565b61309e9190614994565b6130a890876147b3565b905060006130b5826134e6565b905060006130d1846bffffffffffffffffffffffff84166145c5565b905060006130ed68ffffffffffffffffff808916908a16614766565b905061310f61310a6bffffffffffffffffffffffff8316846147b3565b613515565b9a9950505050505050505050565b6000613127610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161315a999897969594939291906149a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613260576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906132ed9190614a74565b905060006132fa3a6134e6565b905060008261012001518361010001516133149190614b3c565b6133259064ffffffffff168361478b565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff16886133849190614766565b338b6040518763ffffffff1660e01b81526004016133a796959493929190614b5a565b60408051808303816000875af11580156133c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e99190614bd6565b9092509050600082600681111561340257613402614572565b148061341f5750600182600681111561341d5761341d614572565b145b156134d85760008b81526007602052604081205561343d8184614766565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff909216939092916134a991859116614766565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b600061350f6134f361240f565b61350584670de0b6b3a76400006145c5565b61310a9190614994565b92915050565b60006bffffffffffffffffffffffff8211156135b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126135e857600080fd5b50813567ffffffffffffffff81111561360057600080fd5b60208301915083602082850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b823567ffffffffffffffff81111561364957600080fd5b613655858286016135d6565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156136b4576136b4613661565b60405290565b604051610160810167ffffffffffffffff811182821017156136b4576136b4613661565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561372557613725613661565b604052919050565b63ffffffff8116811461267957600080fd5b80356111708161372d565b68ffffffffffffffffff8116811461267957600080fd5b80356111708161374a565b64ffffffffff8116811461267957600080fd5b80356111708161376c565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b600061012082840312156137db57600080fd5b6137e3613690565b6137ec8361373f565b81526137fa6020840161373f565b602082015261380b6040840161373f565b604082015261381c6060840161373f565b606082015261382d60808401613761565b608082015261383e60a0840161377f565b60a082015261384f60c0840161378a565b60c082015261386060e0840161379c565b60e082015261010061387381850161373f565b908201529392505050565b6000815180845260005b818110156138a457602081850181015186830182015201613888565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006138f5602083018461387e565b9392505050565b600082601f83011261390d57600080fd5b813567ffffffffffffffff81111561392757613927613661565b61395860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016136de565b81815284602083860101111561396d57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561399c57600080fd5b813567ffffffffffffffff8111156139b357600080fd5b6139bf848285016138fc565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b8035611170816139c7565b6bffffffffffffffffffffffff8116811461267957600080fd5b8035611170816139f4565b60008060408385031215613a2c57600080fd5b8235613a37816139c7565b91506020830135613a47816139f4565b809150509250929050565b600081518084526020808501945080840160005b83811015613a9857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613a66565b509495945050505050565b6020815260006138f56020830184613a52565b600060208284031215613ac857600080fd5b5035919050565b600060208284031215613ae157600080fd5b813567ffffffffffffffff811115613af857600080fd5b820161016081850312156138f557600080fd5b805182526020810151613b36602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613b5660408401826bffffffffffffffffffffffff169052565b506060810151613b7e606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613b9a608084018267ffffffffffffffff169052565b5060a0810151613bb260a084018263ffffffff169052565b5060c0810151613bcf60c084018268ffffffffffffffffff169052565b5060e0810151613bec60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161350f8284613b0b565b60008083601f840112613c4557600080fd5b50813567ffffffffffffffff811115613c5d57600080fd5b6020830191508360208260051b850101111561361857600080fd5b60008060008060008060008060e0898b031215613c9457600080fd5b606089018a811115613ca557600080fd5b8998503567ffffffffffffffff80821115613cbf57600080fd5b613ccb8c838d016135d6565b909950975060808b0135915080821115613ce457600080fd5b613cf08c838d01613c33565b909750955060a08b0135915080821115613d0957600080fd5b50613d168b828c01613c33565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151613d83608084018268ffffffffffffffffff169052565b5060a0830151613d9c60a084018264ffffffffff169052565b5060c0830151613db260c084018261ffff169052565b5060e0830151613de260e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b803561117081613dfe565b600080600080600060808688031215613e3757600080fd5b8535613e4281613dfe565b9450602086013567ffffffffffffffff811115613e5e57600080fd5b613e6a888289016135d6565b9095509350506040860135613e7e8161372d565b949793965091946060013592915050565b600067ffffffffffffffff821115613ea957613ea9613661565b5060051b60200190565b600082601f830112613ec457600080fd5b81356020613ed9613ed483613e8f565b6136de565b82815260059290921b84018101918181019086841115613ef857600080fd5b8286015b84811015613f1c578035613f0f816139c7565b8352918301918301613efc565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c08789031215613f5157600080fd5b863567ffffffffffffffff80821115613f6957600080fd5b613f758a838b01613eb3565b97506020890135915080821115613f8b57600080fd5b613f978a838b01613eb3565b9650613fa560408a01613f27565b95506060890135915080821115613fbb57600080fd5b613fc78a838b016138fc565b9450613fd560808a01613e14565b935060a0890135915080821115613feb57600080fd5b50613ff889828a016138fc565b9150509295509295509295565b60006020828403121561401757600080fd5b81356138f5816139c7565b600181811c9082168061403657607f821691505b60208210810361406f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561409c5750805b601f850160051c820191505b81811015610a88578281556001016140a8565b67ffffffffffffffff8311156140d3576140d3613661565b6140e7836140e18354614022565b83614075565b6000601f84116001811461413957600085156141035750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556141cf565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156141885786850135825560209485019460019092019101614168565b50868210156141c3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b80516111708161374a565b6000602082840312156141f357600080fd5b81516138f58161374a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036142b2576142b26141fe565b5060010190565b600061016082360312156142cc57600080fd5b6142d46136ba565b823567ffffffffffffffff8111156142eb57600080fd5b6142f7368286016138fc565b82525060208301356020820152614310604084016139e9565b604082015261432160608401613a0e565b606082015261433260808401613761565b608082015261434360a08401613e14565b60a082015261435460c08401613e14565b60c082015261436560e0840161373f565b60e082015261010061437881850161378a565b9082015261012061438a848201613e14565b9082015261014061439c8482016139e9565b9082015292915050565b6000602082840312156143b857600080fd5b81356138f581613dfe565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126143f857600080fd5b83018035915067ffffffffffffffff82111561441357600080fd5b60200191503681900382131561361857600080fd5b60006020828403121561443a57600080fd5b6138f58261378a565b60006020828403121561445557600080fd5b81356138f58161372d565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061310f60e0830184613b0b565b60ff818116838216019081111561350f5761350f6141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061456357614563614521565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761350f5761350f6141fe565b8181038181111561350f5761350f6141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616141fe565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261466b8184018a613a52565b9050828103608084015261467f8189613a52565b905060ff871660a084015282810360c084015261469c818761387e565b905067ffffffffffffffff851660e08401528281036101008401526146c1818561387e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a0868803121561470357600080fd5b61470c866146d1565b945060208601519350604086015192506060860151915061472f608087016146d1565b90509295509295909350565b60006bffffffffffffffffffffffff8084168061475a5761475a614521565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616141fe565b6bffffffffffffffffffffffff818116838216028082169190828114613df657613df66141fe565b8082018082111561350f5761350f6141fe565b67ffffffffffffffff818116838216019080821115612661576126616141fe565b600082601f8301126147f857600080fd5b81356020614808613ed483613e8f565b82815260059290921b8401810191818101908684111561482757600080fd5b8286015b84811015613f1c578035835291830191830161482b565b600082601f83011261485357600080fd5b81356020614863613ed483613e8f565b82815260059290921b8401810191818101908684111561488257600080fd5b8286015b84811015613f1c57803567ffffffffffffffff8111156148a65760008081fd5b6148b48986838b01016138fc565b845250918301918301614886565b600080600080600060a086880312156148da57600080fd5b853567ffffffffffffffff808211156148f257600080fd5b6148fe89838a016147e7565b9650602088013591508082111561491457600080fd5b61492089838a01614842565b9550604088013591508082111561493657600080fd5b61494289838a01614842565b9450606088013591508082111561495857600080fd5b61496489838a01614842565b9350608088013591508082111561497a57600080fd5b5061498788828901614842565b9150509295509295909350565b6000826149a3576149a3614521565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526149ef8285018b613a52565b91508382036080850152614a03828a613a52565b915060ff881660a085015283820360c0850152614a20828861387e565b90861660e085015283810361010085015290506146c1818561387e565b8051611170816139c7565b8051611170816139f4565b805161117081613dfe565b80516111708161372d565b80516111708161376c565b60006101608284031215614a8757600080fd5b614a8f6136ba565b82518152614a9f60208401614a3d565b6020820152614ab060408401614a48565b6040820152614ac160608401614a3d565b6060820152614ad260808401614a53565b6080820152614ae360a08401614a5e565b60a0820152614af460c084016141d6565b60c0820152614b0560e084016141d6565b60e0820152610100614b18818501614a69565b90820152610120614b2a848201614a69565b90820152610140613873848201614a5e565b64ffffffffff818116838216019080821115612661576126616141fe565b6000610200808352614b6e8184018a61387e565b90508281036020840152614b82818961387e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614bcb905060a0830184613b0b565b979650505050505050565b60008060408385031215614be957600080fd5b825160078110614bf857600080fd5b6020840151909250613a47816139f456fea164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI @@ -1689,7 +1690,7 @@ func (FunctionsCoordinatorConfigSet) Topic() common.Hash { } func (FunctionsCoordinatorConfigUpdated) Topic() common.Hash { - return common.HexToHash("0x8efd15b0efe82b55a8dc915f88e835007cc65ad0b442997d3c10604961e3907a") + return common.HexToHash("0x5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862") } func (FunctionsCoordinatorOracleRequest) Topic() common.Hash { diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 6b77b889e3b..cff49cd07c2 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,14 +1,14 @@ GETH_VERSION: 1.12.0 -functions: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRequest.bin 3c972870b0afeb6d73a29ebb182f24956a2cebb127b21c4f867d1ecf19a762db -functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_0_0/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 +functions: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.bin 3c972870b0afeb6d73a29ebb182f24956a2cebb127b21c4f867d1ecf19a762db +functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 -functions_client: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca -functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsCoordinator.bin 21bd322caf977c4802d2c17419b57487cca438c7c5fafc52a9a9e1c9f4a72289 -functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de +functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca +functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 9e11effc1922d258d3fc38564b87f4466c56162f33d553ec6d66edcfa55923af +functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c -functions_router: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f -functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d +functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f +functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d ocr2dr: ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.bin d9a794b33f47cc57563d216f7cf3a612309fc3062356a27e30005cf1d59e449d ocr2dr_client: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.bin 84aa63f9dbc5c7eac240db699b09e613ca4c6cd56dab10bdc25b02461b717e21 ocr2dr_client_example: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClientExample.bin a978d9b52a5a2da19eef0975979de256e62980a0cfb3084fe6d66a351b4ef534 diff --git a/core/gethwrappers/functions/go_generate.go b/core/gethwrappers/functions/go_generate.go index 2cb6c4ffaec..0538518da2d 100644 --- a/core/gethwrappers/functions/go_generate.go +++ b/core/gethwrappers/functions/go_generate.go @@ -4,19 +4,12 @@ package gethwrappers // Chainlink Functions (OCR2DR) -// Version 0 (Testnet Beta) -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.bin OCR2DR ocr2dr -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.bin OCR2DRClient ocr2dr_client -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClientExample.bin OCR2DRClientExample ocr2dr_client_example -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleWithInit.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleWithInit.bin OCR2DROracle ocr2dr_oracle -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryWithInit.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryWithInit.bin OCR2DRRegistry ocr2dr_registry - // Version 1 (Mainnet Preview) -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRequest.bin Functions functions -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClient.bin FunctionsClient functions_client -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsClientExample.bin FunctionsClientExample functions_client_example -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsLoadTestClient.bin FunctionsLoadTestClient functions_load_test_client -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsCoordinator.bin FunctionsCoordinator functions_coordinator -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsRouter.bin FunctionsRouter functions_router -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/TermsOfServiceAllowList.bin TermsOfServiceAllowList functions_allow_list -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_0_0/FunctionsV1EventsMock.bin FunctionsV1EventsMock functions_v1_events_mock +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.bin Functions functions +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin FunctionsClient functions_client +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin FunctionsClientExample functions_client_example +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin FunctionsLoadTestClient functions_load_test_client +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin FunctionsCoordinator functions_coordinator +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin FunctionsRouter functions_router +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin TermsOfServiceAllowList functions_allow_list +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.bin FunctionsV1EventsMock functions_v1_events_mock diff --git a/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go b/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go index 8fea978228d..6417a9c6782 100644 --- a/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go +++ b/core/gethwrappers/generated/authorized_forwarder/authorized_forwarder.go @@ -31,8 +31,8 @@ var ( ) var AuthorizedForwarderMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"OwnershipTransferRequestedWithMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"forward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"transferOwnershipWithMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200133538038062001335833981810160405260808110156200003757600080fd5b8151602083015160408085015160608601805192519496939591949391820192846401000000008211156200006b57600080fd5b9083019060208201858111156200008157600080fd5b82516401000000008111828201881017156200009c57600080fd5b82525081516020918201929091019080838360005b83811015620000cb578181015183820152602001620000b1565b50505050905090810190601f168015620000f95780820380516001836020036101000a031916815260200191505b50604052508491508390506001600160a01b03821662000160576040805162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200019357620001938162000286565b50506001600160a01b038416620001a957600080fd5b6001600160601b0319606085901b166080526001600160a01b038216156200027c57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040518080602001828103825283818151815260200191508051906020019080838360005b838110156200024057818101518382015260200162000226565b50505050905090810190601f1680156200026e5780820380516001836020036101000a031916815260200191505b509250505060405180910390a35b5050505062000336565b6001600160a01b038116331415620002e5576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60805160601c610fdc6200035960003980610491528061061d5250610fdc6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636fadcf7211610081578063ee56997b1161005b578063ee56997b1461038d578063f2fde38b146103fd578063fa00763a14610430576100c9565b80636fadcf72146102f057806379ba50971461037d5780638da5cb5b14610385576100c9565b8063181f5a77116100b2578063181f5a771461018e5780632408afaa1461020b5780634d3e232314610263576100c9565b8063033f49f7146100ce578063165d35e11461015d575b600080fd5b61015b600480360360408110156100e457600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561011c57600080fd5b82018360208201111561012e57600080fd5b8035906020019184600183028401116401000000008311171561015057600080fd5b509092509050610477565b005b61016561048f565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101966104b3565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101d05781810151838201526020016101b8565b50505050905090810190601f1680156101fd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102136104ea565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561024f578181015183820152602001610237565b505050509050019250505060405180910390f35b61015b6004803603604081101561027957600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156102b157600080fd5b8201836020820111156102c357600080fd5b803590602001918460018302840111640100000000831117156102e557600080fd5b509092509050610559565b61015b6004803603604081101561030657600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561033e57600080fd5b82018360208201111561035057600080fd5b8035906020019184600183028401116401000000008311171561037257600080fd5b509092509050610613565b61015b6106d6565b6101656107d8565b61015b600480360360208110156103a357600080fd5b8101906020810181356401000000008111156103be57600080fd5b8201836020820111156103d057600080fd5b803590602001918460208302840111640100000000831117156103f257600080fd5b5090925090506107f4565b61015b6004803603602081101561041357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610b3e565b6104636004803603602081101561044657600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610b52565b604080519115158252519081900360200190f35b61047f610b7d565b61048a838383610c05565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60408051808201909152601981527f417574686f72697a6564466f7277617264657220312e302e3000000000000000602082015290565b6060600380548060200260200160405190810160405280929190818152602001828054801561054f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610524575b5050505050905090565b61056283610b3e565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a3505050565b61061b610d70565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561047f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e00000000604482015290519081900360640190fd5b60015473ffffffffffffffffffffffffffffffffffffffff16331461075c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015290519081900360640190fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b6107fc610de4565b61086757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b806108d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e6465720000000000604482015290519081900360640190fd5b60035460005b8181101561095b57600060026000600384815481106108f457fe5b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556001016108d9565b5060005b82811015610a8c576002600085858481811061097757fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168352508101919091526040016000205460ff1615610a1657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e6465727300604482015290519081900360640190fd5b600160026000868685818110610a2857fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff1683525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560010161095f565b50610a9960038484610f0c565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405180806020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252858582818152602001925060200280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b610b46610b7d565b610b4f81610e0b565b50565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b565b610c248373ffffffffffffffffffffffffffffffffffffffff16610f06565b610c8f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e7472616374000000000000604482015290519081900360640190fd5b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284376040519201945060009350909150508083038183865af19150503d8060008114610cfb576040519150601f19603f3d011682016040523d82523d6000602084013e610d00565b606091505b509150915081610d69578051610d61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180610faa6026913960400191505060405180910390fd5b805181602001fd5b5050505050565b610d7933610b52565b610c0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e6465720000000000000000000000604482015290519081900360640190fd5b600033610def6107d8565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610e9057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b3b151590565b828054828255906000526020600020908101928215610f84579160200282015b82811115610f845781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610f2c565b50610f90929150610f94565b5090565b5b80821115610f905760008155600101610f9556fe466f727761726465642063616c6c20726576657274656420776974686f757420726561736f6ea164736f6c6343000706000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"OwnershipTransferRequestedWithMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"forward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tos\",\"type\":\"address[]\"},{\"internalType\":\"bytes[]\",\"name\":\"datas\",\"type\":\"bytes[]\"}],\"name\":\"multiForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"transferOwnershipWithMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000a", } var AuthorizedForwarderABI = AuthorizedForwarderMetaData.ABI @@ -193,48 +193,48 @@ func (_AuthorizedForwarder *AuthorizedForwarderCallerSession) GetAuthorizedSende return _AuthorizedForwarder.Contract.GetAuthorizedSenders(&_AuthorizedForwarder.CallOpts) } -func (_AuthorizedForwarder *AuthorizedForwarderCaller) GetChainlinkToken(opts *bind.CallOpts) (common.Address, error) { +func (_AuthorizedForwarder *AuthorizedForwarderCaller) IsAuthorizedSender(opts *bind.CallOpts, sender common.Address) (bool, error) { var out []interface{} - err := _AuthorizedForwarder.contract.Call(opts, &out, "getChainlinkToken") + err := _AuthorizedForwarder.contract.Call(opts, &out, "isAuthorizedSender", sender) if err != nil { - return *new(common.Address), err + return *new(bool), err } - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err } -func (_AuthorizedForwarder *AuthorizedForwarderSession) GetChainlinkToken() (common.Address, error) { - return _AuthorizedForwarder.Contract.GetChainlinkToken(&_AuthorizedForwarder.CallOpts) +func (_AuthorizedForwarder *AuthorizedForwarderSession) IsAuthorizedSender(sender common.Address) (bool, error) { + return _AuthorizedForwarder.Contract.IsAuthorizedSender(&_AuthorizedForwarder.CallOpts, sender) } -func (_AuthorizedForwarder *AuthorizedForwarderCallerSession) GetChainlinkToken() (common.Address, error) { - return _AuthorizedForwarder.Contract.GetChainlinkToken(&_AuthorizedForwarder.CallOpts) +func (_AuthorizedForwarder *AuthorizedForwarderCallerSession) IsAuthorizedSender(sender common.Address) (bool, error) { + return _AuthorizedForwarder.Contract.IsAuthorizedSender(&_AuthorizedForwarder.CallOpts, sender) } -func (_AuthorizedForwarder *AuthorizedForwarderCaller) IsAuthorizedSender(opts *bind.CallOpts, sender common.Address) (bool, error) { +func (_AuthorizedForwarder *AuthorizedForwarderCaller) LinkToken(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _AuthorizedForwarder.contract.Call(opts, &out, "isAuthorizedSender", sender) + err := _AuthorizedForwarder.contract.Call(opts, &out, "linkToken") if err != nil { - return *new(bool), err + return *new(common.Address), err } - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) return out0, err } -func (_AuthorizedForwarder *AuthorizedForwarderSession) IsAuthorizedSender(sender common.Address) (bool, error) { - return _AuthorizedForwarder.Contract.IsAuthorizedSender(&_AuthorizedForwarder.CallOpts, sender) +func (_AuthorizedForwarder *AuthorizedForwarderSession) LinkToken() (common.Address, error) { + return _AuthorizedForwarder.Contract.LinkToken(&_AuthorizedForwarder.CallOpts) } -func (_AuthorizedForwarder *AuthorizedForwarderCallerSession) IsAuthorizedSender(sender common.Address) (bool, error) { - return _AuthorizedForwarder.Contract.IsAuthorizedSender(&_AuthorizedForwarder.CallOpts, sender) +func (_AuthorizedForwarder *AuthorizedForwarderCallerSession) LinkToken() (common.Address, error) { + return _AuthorizedForwarder.Contract.LinkToken(&_AuthorizedForwarder.CallOpts) } func (_AuthorizedForwarder *AuthorizedForwarderCaller) Owner(opts *bind.CallOpts) (common.Address, error) { @@ -305,6 +305,18 @@ func (_AuthorizedForwarder *AuthorizedForwarderTransactorSession) Forward(to com return _AuthorizedForwarder.Contract.Forward(&_AuthorizedForwarder.TransactOpts, to, data) } +func (_AuthorizedForwarder *AuthorizedForwarderTransactor) MultiForward(opts *bind.TransactOpts, tos []common.Address, datas [][]byte) (*types.Transaction, error) { + return _AuthorizedForwarder.contract.Transact(opts, "multiForward", tos, datas) +} + +func (_AuthorizedForwarder *AuthorizedForwarderSession) MultiForward(tos []common.Address, datas [][]byte) (*types.Transaction, error) { + return _AuthorizedForwarder.Contract.MultiForward(&_AuthorizedForwarder.TransactOpts, tos, datas) +} + +func (_AuthorizedForwarder *AuthorizedForwarderTransactorSession) MultiForward(tos []common.Address, datas [][]byte) (*types.Transaction, error) { + return _AuthorizedForwarder.Contract.MultiForward(&_AuthorizedForwarder.TransactOpts, tos, datas) +} + func (_AuthorizedForwarder *AuthorizedForwarderTransactor) OwnerForward(opts *bind.TransactOpts, to common.Address, data []byte) (*types.Transaction, error) { return _AuthorizedForwarder.contract.Transact(opts, "ownerForward", to, data) } @@ -919,10 +931,10 @@ func (_AuthorizedForwarder *AuthorizedForwarder) Address() common.Address { type AuthorizedForwarderInterface interface { GetAuthorizedSenders(opts *bind.CallOpts) ([]common.Address, error) - GetChainlinkToken(opts *bind.CallOpts) (common.Address, error) - IsAuthorizedSender(opts *bind.CallOpts, sender common.Address) (bool, error) + LinkToken(opts *bind.CallOpts) (common.Address, error) + Owner(opts *bind.CallOpts) (common.Address, error) TypeAndVersion(opts *bind.CallOpts) (string, error) @@ -931,6 +943,8 @@ type AuthorizedForwarderInterface interface { Forward(opts *bind.TransactOpts, to common.Address, data []byte) (*types.Transaction, error) + MultiForward(opts *bind.TransactOpts, tos []common.Address, datas [][]byte) (*types.Transaction, error) + OwnerForward(opts *bind.TransactOpts, to common.Address, data []byte) (*types.Transaction, error) SetAuthorizedSenders(opts *bind.TransactOpts, senders []common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go index 9f799c49376..426c5a2c79d 100644 --- a/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go +++ b/core/gethwrappers/generated/batch_blockhash_store/batch_blockhash_store.go @@ -30,7 +30,7 @@ var ( var BatchBlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStoreAddr\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BHS\",\"outputs\":[{\"internalType\":\"contractBlockhashStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"}],\"name\":\"getBlockhashes\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNumbers\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"headers\",\"type\":\"bytes[]\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051610b81380380610b8183398101604081905261002f91610044565b60601b6001600160601b031916608052610074565b60006020828403121561005657600080fd5b81516001600160a01b038116811461006d57600080fd5b9392505050565b60805160601c610adb6100a66000396000818160a7015281816101270152818161023a01526104290152610adb6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806306bd010d146100515780631f600f86146100665780635d290e211461008f578063f745eafb146100a2575b600080fd5b61006461005f366004610654565b6100ee565b005b610079610074366004610654565b6101e2565b60405161008691906107ff565b60405180910390f35b61006461009d366004610691565b6103ac565b6100c97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b60005b81518110156101de5761011c82828151811061010f5761010f6109ac565b60200260200101516104fe565b610125576101cc565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636057361d838381518110610173576101736109ac565b60200260200101516040518263ffffffff1660e01b815260040161019991815260200190565b600060405180830381600087803b1580156101b357600080fd5b505af11580156101c7573d6000803e3d6000fd5b505050505b806101d681610944565b9150506100f1565b5050565b60606000825167ffffffffffffffff811115610200576102006109db565b604051908082528060200260200182016040528015610229578160200160208202803683370190505b50905060005b83518110156103a5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e9413d38858381518110610286576102866109ac565b60200260200101516040518263ffffffff1660e01b81526004016102ac91815260200190565b60206040518083038186803b1580156102c457600080fd5b505afa925050508015610312575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261030f918101906107e6565b60015b6103725761031e610a0a565b806308c379a014156103665750610333610a26565b8061033e5750610368565b6000801b838381518110610354576103546109ac565b60200260200101818152505050610393565b505b3d6000803e3d6000fd5b80838381518110610385576103856109ac565b602002602001018181525050505b8061039d81610944565b91505061022f565b5092915050565b805182511461041b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b82518110156104f9577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fadff0e1848381518110610475576104756109ac565b602002602001015184848151811061048f5761048f6109ac565b60200260200101516040518363ffffffff1660e01b81526004016104b4929190610843565b600060405180830381600087803b1580156104ce57600080fd5b505af11580156104e2573d6000803e3d6000fd5b5050505080806104f190610944565b91505061041e565b505050565b600061010061050b610537565b111561052e5761010061051c610537565b61052691906108e2565b821015610531565b60015b92915050565b60004661a4b181148061054c575062066eed81145b156105d657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561059857600080fd5b505afa1580156105ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d091906107e6565b91505090565b4391505090565b600082601f8301126105ee57600080fd5b813560206105fb826108be565b60405161060882826108f9565b8381528281019150858301600585901b8701840188101561062857600080fd5b60005b858110156106475781358452928401929084019060010161062b565b5090979650505050505050565b60006020828403121561066657600080fd5b813567ffffffffffffffff81111561067d57600080fd5b610689848285016105dd565b949350505050565b60008060408084860312156106a557600080fd5b833567ffffffffffffffff808211156106bd57600080fd5b6106c9878388016105dd565b94506020915081860135818111156106e057600080fd5b8601601f810188136106f157600080fd5b80356106fc816108be565b855161070882826108f9565b8281528581019150838601600584901b850187018c101561072857600080fd5b60005b848110156107d45781358781111561074257600080fd5b8601603f81018e1361075357600080fd5b8881013588811115610767576107676109db565b8a5161079a8b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011601826108f9565b8181528f8c8385010111156107ae57600080fd5b818c84018c83013760009181018b0191909152855250928701929087019060010161072b565b50989b909a5098505050505050505050565b6000602082840312156107f857600080fd5b5051919050565b6020808252825182820181905260009190848201906040850190845b818110156108375783518352928401929184019160010161081b565b50909695505050505050565b82815260006020604081840152835180604085015260005b818110156108775785810183015185820160600152820161085b565b81811115610889576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b600067ffffffffffffffff8211156108d8576108d86109db565b5060051b60200190565b6000828210156108f4576108f461097d565b500390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff8211171561093d5761093d6109db565b6040525050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156109765761097661097d565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610a235760046000803e5060005160e01c5b90565b600060443d1015610a345790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610a8257505050505090565b8285019150815181811115610a9a5750505050505090565b843d8701016020828501011115610ab45750505050505090565b610ac3602082860101876108f9565b50909594505050505056fea164736f6c6343000806000a", + Bin: "0x60a060405234801561001057600080fd5b50604051610b9b380380610b9b83398101604081905261002f91610044565b60601b6001600160601b031916608052610074565b60006020828403121561005657600080fd5b81516001600160a01b038116811461006d57600080fd5b9392505050565b60805160601c610af56100a66000396000818160a7015281816101270152818161023a01526104290152610af56000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806306bd010d146100515780631f600f86146100665780635d290e211461008f578063f745eafb146100a2575b600080fd5b61006461005f36600461066e565b6100ee565b005b61007961007436600461066e565b6101e2565b6040516100869190610819565b60405180910390f35b61006461009d3660046106ab565b6103ac565b6100c97f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b60005b81518110156101de5761011c82828151811061010f5761010f6109c6565b60200260200101516104fe565b610125576101cc565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636057361d838381518110610173576101736109c6565b60200260200101516040518263ffffffff1660e01b815260040161019991815260200190565b600060405180830381600087803b1580156101b357600080fd5b505af11580156101c7573d6000803e3d6000fd5b505050505b806101d68161095e565b9150506100f1565b5050565b60606000825167ffffffffffffffff811115610200576102006109f5565b604051908082528060200260200182016040528015610229578160200160208202803683370190505b50905060005b83518110156103a5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e9413d38858381518110610286576102866109c6565b60200260200101516040518263ffffffff1660e01b81526004016102ac91815260200190565b60206040518083038186803b1580156102c457600080fd5b505afa925050508015610312575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261030f91810190610800565b60015b6103725761031e610a24565b806308c379a014156103665750610333610a40565b8061033e5750610368565b6000801b838381518110610354576103546109c6565b60200260200101818152505050610393565b505b3d6000803e3d6000fd5b80838381518110610385576103856109c6565b602002602001018181525050505b8061039d8161095e565b91505061022f565b5092915050565b805182511461041b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f696e70757420617272617920617267206c656e67746873206d69736d61746368604482015260640160405180910390fd5b60005b82518110156104f9577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fadff0e1848381518110610475576104756109c6565b602002602001015184848151811061048f5761048f6109c6565b60200260200101516040518363ffffffff1660e01b81526004016104b492919061085d565b600060405180830381600087803b1580156104ce57600080fd5b505af11580156104e2573d6000803e3d6000fd5b5050505080806104f19061095e565b91505061041e565b505050565b600061010061050b610537565b111561052e5761010061051c610537565b61052691906108fc565b821015610531565b60015b92915050565b600046610543816105d4565b156105cd57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561058f57600080fd5b505afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c79190610800565b91505090565b4391505090565b600061a4b18214806105e8575062066eed82145b8061053157505062066eee1490565b600082601f83011261060857600080fd5b81356020610615826108d8565b6040516106228282610913565b8381528281019150858301600585901b8701840188101561064257600080fd5b60005b8581101561066157813584529284019290840190600101610645565b5090979650505050505050565b60006020828403121561068057600080fd5b813567ffffffffffffffff81111561069757600080fd5b6106a3848285016105f7565b949350505050565b60008060408084860312156106bf57600080fd5b833567ffffffffffffffff808211156106d757600080fd5b6106e3878388016105f7565b94506020915081860135818111156106fa57600080fd5b8601601f8101881361070b57600080fd5b8035610716816108d8565b85516107228282610913565b8281528581019150838601600584901b850187018c101561074257600080fd5b60005b848110156107ee5781358781111561075c57600080fd5b8601603f81018e1361076d57600080fd5b8881013588811115610781576107816109f5565b8a516107b48b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160182610913565b8181528f8c8385010111156107c857600080fd5b818c84018c83013760009181018b01919091528552509287019290870190600101610745565b50989b909a5098505050505050505050565b60006020828403121561081257600080fd5b5051919050565b6020808252825182820181905260009190848201906040850190845b8181101561085157835183529284019291840191600101610835565b50909695505050505050565b82815260006020604081840152835180604085015260005b8181101561089157858101830151858201606001528201610875565b818111156108a3576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b600067ffffffffffffffff8211156108f2576108f26109f5565b5060051b60200190565b60008282101561090e5761090e610997565b500390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715610957576109576109f5565b6040525050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561099057610990610997565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060033d1115610a3d5760046000803e5060005160e01c5b90565b600060443d1015610a4e5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715610a9c57505050505090565b8285019150815181811115610ab45750505050505090565b843d8701016020828501011115610ace5750505050505090565b610add60208286010187610913565b50909594505050505056fea164736f6c6343000806000a", } var BatchBlockhashStoreABI = BatchBlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/blockhash_store/blockhash_store.go b/core/gethwrappers/generated/blockhash_store/blockhash_store.go index 449df2715ea..8711f13b2d6 100644 --- a/core/gethwrappers/generated/blockhash_store/blockhash_store.go +++ b/core/gethwrappers/generated/blockhash_store/blockhash_store.go @@ -30,7 +30,7 @@ var ( var BlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storeEarliest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506104b1806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610070578063e9413d3814610078578063fadff0e1146100a7575b600080fd5b61006e6004803603602081101561006757600080fd5b5035610154565b005b61006e6101df565b6100956004803603602081101561008e57600080fd5b50356101f5565b60408051918252519081900360200190f35b61006e600480360360408110156100bd57600080fd5b813591908101906040810160208201356401000000008111156100df57600080fd5b8201836020820111156100f157600080fd5b8035906020019184600183028401116401000000008311171561011357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610278945050505050565b600061015f82610318565b9050806101cd57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c656400000000000000000000000000604482015290519081900360640190fd5b60009182526020829052604090912055565b6101f36101006101ed6103f8565b03610154565b565b6000818152602081905260408120548061027057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f726500000000604482015290519081900360640190fd5b90505b919050565b6000808360010181526020019081526020016000205481805190602001201461030257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b6861736800000000604482015290519081900360640190fd5b6024015160009182526020829052604090912055565b6000806103236104a0565b905061a4b1811480610337575062066eed81145b156103f257610100836103486103f8565b03118061035c57506103586103f8565b8310155b1561036b576000915050610273565b606473ffffffffffffffffffffffffffffffffffffffff16632b407a82846040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156103bd57600080fd5b505afa1580156103d1573d6000803e3d6000fd5b505050506040513d60208110156103e757600080fd5b505191506102739050565b50504090565b6000806104036104a0565b905061a4b1811480610417575062066eed81145b1561049857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561046357600080fd5b505afa158015610477573d6000803e3d6000fd5b505050506040513d602081101561048d57600080fd5b5051915061049d9050565b439150505b90565b469056fea164736f6c6343000606000a", + Bin: "0x608060405234801561001057600080fd5b506105d3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610066578063e9413d381461006e578063fadff0e114610093575b600080fd5b61006461005f366004610447565b6100a6565b005b610064610131565b61008161007c366004610447565b61014b565b60405190815260200160405180910390f35b6100646100a1366004610460565b6101c7565b60006100b182610269565b90508061011f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526020829052604090912055565b61014961010061013f61036e565b61005f9190610551565b565b600081815260208190526040812054806101c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f7265000000006044820152606401610116565b92915050565b6000806101d5846001610539565b815260200190815260200160002054818051906020012014610253576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b68617368000000006044820152606401610116565b6024015160009182526020829052604090912055565b6000466102758161040b565b1561035e576101008367ffffffffffffffff1661029061036e565b61029a9190610551565b11806102b757506102a961036e565b8367ffffffffffffffff1610155b156102c55750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b15801561031f57600080fd5b505afa158015610333573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610357919061042e565b9392505050565b505067ffffffffffffffff164090565b60004661037a8161040b565b1561040457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156103c657600080fd5b505afa1580156103da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103fe919061042e565b91505090565b4391505090565b600061a4b182148061041f575062066eed82145b806101c157505062066eee1490565b60006020828403121561044057600080fd5b5051919050565b60006020828403121561045957600080fd5b5035919050565b6000806040838503121561047357600080fd5b82359150602083013567ffffffffffffffff8082111561049257600080fd5b818501915085601f8301126104a657600080fd5b8135818111156104b8576104b8610597565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104fe576104fe610597565b8160405282815288602084870101111561051757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000821982111561054c5761054c610568565b500190565b60008282101561056357610563610568565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var BlockhashStoreABI = BlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go b/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go new file mode 100644 index 00000000000..aa4dc0f88d9 --- /dev/null +++ b/core/gethwrappers/generated/chain_specific_util_helper/chain_specific_util_helper.go @@ -0,0 +1,274 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package chain_specific_util_helper + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var ChainSpecificUtilHelperMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockNumber\",\"type\":\"uint64\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"txCallData\",\"type\":\"string\"}],\"name\":\"getCurrentTxL1GasFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"calldataSize\",\"type\":\"uint256\"}],\"name\":\"getL1CalldataGasCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50610c1a806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806342cbb15c1461005157806397e329a91461006b578063b778b1121461007e578063da9027ef14610091575b600080fd5b6100596100a4565b60405190815260200160405180910390f35b6100596100793660046108bf565b6100b3565b61005961008c36600461085c565b6100c4565b61005961009f36600461078d565b6100cf565b60006100ae6100da565b905090565b60006100be82610177565b92915050565b60006100be8261027d565b60006100be82610355565b6000466100e681610441565b1561017057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561013257600080fd5b505afa158015610146573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061016a9190610774565b91505090565b4391505090565b60004661018381610441565b1561026d576101008367ffffffffffffffff1661019e6100da565b6101a89190610b20565b11806101c557506101b76100da565b8367ffffffffffffffff1610155b156101d35750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a82906024015b60206040518083038186803b15801561022e57600080fd5b505afa158015610242573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102669190610774565b9392505050565b505067ffffffffffffffff164090565b60004661028981610441565b15610335576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b1580156102d757600080fd5b505afa1580156102eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030f9190610875565b5050505091505083608c6103239190610969565b61032d9082610ae3565b949350505050565b61033e81610464565b1561034c576102668361049e565b50600092915050565b60004661036181610441565b156103ad57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561022e57600080fd5b6103b681610464565b1561034c5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001610bc6604891396040516020016104169291906108e9565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016102169190610918565b600061a4b1821480610455575062066eed82145b806100be57505062066eee1490565b6000600a82148061047657506101a482145b80610483575062aa37dc82145b8061048f575061210582145b806100be57505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b815260040160206040518083038186803b1580156104fb57600080fd5b505afa15801561050f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105339190610774565b90506000806105428186610b20565b90506000610551826010610ae3565b61055c846004610ae3565b6105669190610969565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b815260040160206040518083038186803b1580156105c457600080fd5b505afa1580156105d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fc9190610774565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b815260040160206040518083038186803b15801561065a57600080fd5b505afa15801561066e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106929190610774565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156106f057600080fd5b505afa158015610704573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107289190610774565b9050600061073782600a610a1d565b9050600081846107478789610969565b610751908c610ae3565b61075b9190610ae3565b6107659190610981565b9b9a5050505050505050505050565b60006020828403121561078657600080fd5b5051919050565b60006020828403121561079f57600080fd5b813567ffffffffffffffff808211156107b757600080fd5b818401915084601f8301126107cb57600080fd5b8135818111156107dd576107dd610b96565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561082357610823610b96565b8160405282815287602084870101111561083c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60006020828403121561086e57600080fd5b5035919050565b60008060008060008060c0878903121561088e57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000602082840312156108d157600080fd5b813567ffffffffffffffff8116811461026657600080fd5b600083516108fb818460208801610b37565b83519083019061090f818360208801610b37565b01949350505050565b6020815260008251806020840152610937816040850160208701610b37565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000821982111561097c5761097c610b67565b500190565b6000826109b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600181815b80851115610a1557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156109fb576109fb610b67565b80851615610a0857918102915b93841c93908002906109c1565b509250929050565b60006102668383600082610a33575060016100be565b81610a40575060006100be565b8160018114610a565760028114610a6057610a7c565b60019150506100be565b60ff841115610a7157610a71610b67565b50506001821b6100be565b5060208310610133831016604e8410600b8410161715610a9f575081810a6100be565b610aa983836109bc565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610adb57610adb610b67565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610b1b57610b1b610b67565b500290565b600082821015610b3257610b32610b67565b500390565b60005b83811015610b52578181015183820152602001610b3a565b83811115610b61576000848401525b50505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", +} + +var ChainSpecificUtilHelperABI = ChainSpecificUtilHelperMetaData.ABI + +var ChainSpecificUtilHelperBin = ChainSpecificUtilHelperMetaData.Bin + +func DeployChainSpecificUtilHelper(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ChainSpecificUtilHelper, error) { + parsed, err := ChainSpecificUtilHelperMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ChainSpecificUtilHelperBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &ChainSpecificUtilHelper{ChainSpecificUtilHelperCaller: ChainSpecificUtilHelperCaller{contract: contract}, ChainSpecificUtilHelperTransactor: ChainSpecificUtilHelperTransactor{contract: contract}, ChainSpecificUtilHelperFilterer: ChainSpecificUtilHelperFilterer{contract: contract}}, nil +} + +type ChainSpecificUtilHelper struct { + address common.Address + abi abi.ABI + ChainSpecificUtilHelperCaller + ChainSpecificUtilHelperTransactor + ChainSpecificUtilHelperFilterer +} + +type ChainSpecificUtilHelperCaller struct { + contract *bind.BoundContract +} + +type ChainSpecificUtilHelperTransactor struct { + contract *bind.BoundContract +} + +type ChainSpecificUtilHelperFilterer struct { + contract *bind.BoundContract +} + +type ChainSpecificUtilHelperSession struct { + Contract *ChainSpecificUtilHelper + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type ChainSpecificUtilHelperCallerSession struct { + Contract *ChainSpecificUtilHelperCaller + CallOpts bind.CallOpts +} + +type ChainSpecificUtilHelperTransactorSession struct { + Contract *ChainSpecificUtilHelperTransactor + TransactOpts bind.TransactOpts +} + +type ChainSpecificUtilHelperRaw struct { + Contract *ChainSpecificUtilHelper +} + +type ChainSpecificUtilHelperCallerRaw struct { + Contract *ChainSpecificUtilHelperCaller +} + +type ChainSpecificUtilHelperTransactorRaw struct { + Contract *ChainSpecificUtilHelperTransactor +} + +func NewChainSpecificUtilHelper(address common.Address, backend bind.ContractBackend) (*ChainSpecificUtilHelper, error) { + abi, err := abi.JSON(strings.NewReader(ChainSpecificUtilHelperABI)) + if err != nil { + return nil, err + } + contract, err := bindChainSpecificUtilHelper(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ChainSpecificUtilHelper{address: address, abi: abi, ChainSpecificUtilHelperCaller: ChainSpecificUtilHelperCaller{contract: contract}, ChainSpecificUtilHelperTransactor: ChainSpecificUtilHelperTransactor{contract: contract}, ChainSpecificUtilHelperFilterer: ChainSpecificUtilHelperFilterer{contract: contract}}, nil +} + +func NewChainSpecificUtilHelperCaller(address common.Address, caller bind.ContractCaller) (*ChainSpecificUtilHelperCaller, error) { + contract, err := bindChainSpecificUtilHelper(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ChainSpecificUtilHelperCaller{contract: contract}, nil +} + +func NewChainSpecificUtilHelperTransactor(address common.Address, transactor bind.ContractTransactor) (*ChainSpecificUtilHelperTransactor, error) { + contract, err := bindChainSpecificUtilHelper(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ChainSpecificUtilHelperTransactor{contract: contract}, nil +} + +func NewChainSpecificUtilHelperFilterer(address common.Address, filterer bind.ContractFilterer) (*ChainSpecificUtilHelperFilterer, error) { + contract, err := bindChainSpecificUtilHelper(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ChainSpecificUtilHelperFilterer{contract: contract}, nil +} + +func bindChainSpecificUtilHelper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ChainSpecificUtilHelperMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ChainSpecificUtilHelper.Contract.ChainSpecificUtilHelperCaller.contract.Call(opts, result, method, params...) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ChainSpecificUtilHelper.Contract.ChainSpecificUtilHelperTransactor.contract.Transfer(opts) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ChainSpecificUtilHelper.Contract.ChainSpecificUtilHelperTransactor.contract.Transact(opts, method, params...) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ChainSpecificUtilHelper.Contract.contract.Call(opts, result, method, params...) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ChainSpecificUtilHelper.Contract.contract.Transfer(opts) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ChainSpecificUtilHelper.Contract.contract.Transact(opts, method, params...) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCaller) GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ChainSpecificUtilHelper.contract.Call(opts, &out, "getBlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperSession) GetBlockNumber() (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetBlockNumber(&_ChainSpecificUtilHelper.CallOpts) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCallerSession) GetBlockNumber() (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetBlockNumber(&_ChainSpecificUtilHelper.CallOpts) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCaller) GetBlockhash(opts *bind.CallOpts, blockNumber uint64) ([32]byte, error) { + var out []interface{} + err := _ChainSpecificUtilHelper.contract.Call(opts, &out, "getBlockhash", blockNumber) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperSession) GetBlockhash(blockNumber uint64) ([32]byte, error) { + return _ChainSpecificUtilHelper.Contract.GetBlockhash(&_ChainSpecificUtilHelper.CallOpts, blockNumber) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCallerSession) GetBlockhash(blockNumber uint64) ([32]byte, error) { + return _ChainSpecificUtilHelper.Contract.GetBlockhash(&_ChainSpecificUtilHelper.CallOpts, blockNumber) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCaller) GetCurrentTxL1GasFees(opts *bind.CallOpts, txCallData string) (*big.Int, error) { + var out []interface{} + err := _ChainSpecificUtilHelper.contract.Call(opts, &out, "getCurrentTxL1GasFees", txCallData) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperSession) GetCurrentTxL1GasFees(txCallData string) (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetCurrentTxL1GasFees(&_ChainSpecificUtilHelper.CallOpts, txCallData) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCallerSession) GetCurrentTxL1GasFees(txCallData string) (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetCurrentTxL1GasFees(&_ChainSpecificUtilHelper.CallOpts, txCallData) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCaller) GetL1CalldataGasCost(opts *bind.CallOpts, calldataSize *big.Int) (*big.Int, error) { + var out []interface{} + err := _ChainSpecificUtilHelper.contract.Call(opts, &out, "getL1CalldataGasCost", calldataSize) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperSession) GetL1CalldataGasCost(calldataSize *big.Int) (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetL1CalldataGasCost(&_ChainSpecificUtilHelper.CallOpts, calldataSize) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelperCallerSession) GetL1CalldataGasCost(calldataSize *big.Int) (*big.Int, error) { + return _ChainSpecificUtilHelper.Contract.GetL1CalldataGasCost(&_ChainSpecificUtilHelper.CallOpts, calldataSize) +} + +func (_ChainSpecificUtilHelper *ChainSpecificUtilHelper) Address() common.Address { + return _ChainSpecificUtilHelper.address +} + +type ChainSpecificUtilHelperInterface interface { + GetBlockNumber(opts *bind.CallOpts) (*big.Int, error) + + GetBlockhash(opts *bind.CallOpts, blockNumber uint64) ([32]byte, error) + + GetCurrentTxL1GasFees(opts *bind.CallOpts, txCallData string) (*big.Int, error) + + GetL1CalldataGasCost(opts *bind.CallOpts, calldataSize *big.Int) (*big.Int, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/derived_price_feed_wrapper/derived_price_feed_wrapper.go b/core/gethwrappers/generated/derived_price_feed_wrapper/derived_price_feed_wrapper.go deleted file mode 100644 index 5e4e4be0e36..00000000000 --- a/core/gethwrappers/generated/derived_price_feed_wrapper/derived_price_feed_wrapper.go +++ /dev/null @@ -1,395 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package derived_price_feed_wrapper - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -var DerivedPriceFeedMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_base\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_quote\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BASE\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMALS\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTE\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"description\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"\",\"type\":\"uint80\"}],\"name\":\"getRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"\",\"type\":\"uint80\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60e060405234801561001057600080fd5b50604051610c14380380610c1483398101604081905261002f916100ec565b60ff8116158015906100455750601260ff821611155b6100895760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964205f646563696d616c7360781b604482015260640160405180910390fd5b60f81b7fff000000000000000000000000000000000000000000000000000000000000001660c052606091821b6001600160601b0319908116608052911b1660a052610139565b80516001600160a01b03811681146100e757600080fd5b919050565b60008060006060848603121561010157600080fd5b61010a846100d0565b9250610118602085016100d0565b9150604084015160ff8116811461012e57600080fd5b809150509250925092565b60805160601c60a05160601c60c05160f81c610a6d6101a76000396000818160920152818160cd0152818161041a0152818161058f01526105bd0152600081816101950152818161044401526104ea0152600081816101e1015281816102cf01526103750152610a6d6000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80639a6fc8f51161005b5780639a6fc8f5146101465780639c57983914610190578063ec342ad0146101dc578063feaf968c1461020357600080fd5b80632e0f26251461008d578063313ce567146100cb57806354fd4d50146100f15780637284e41614610107575b600080fd5b6100b47f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020015b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000006100b4565b6100f9600081565b6040519081526020016100c2565b604080518082018252601481527f446572697665645072696365466565642e736f6c000000000000000000000000602082015290516100c2919061070c565b610159610154366004610674565b61020b565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016100c2565b6101b77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b6101b77f000000000000000000000000000000000000000000000000000000000000000081565b6101596102a6565b60008060008060006040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161029d9060208082526027908201527f6e6f7420696d706c656d656e746564202d20757365206c6174657374526f756e60408201527f6444617461282900000000000000000000000000000000000000000000000000606082015260800190565b60405180910390fd5b6000806000806000806102b76102ca565b9096909550429450849350600092509050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561033357600080fd5b505afa158015610347573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061036b9190610691565b50505091505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156103d957600080fd5b505afa1580156103ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041191906106e9565b905061043e82827f0000000000000000000000000000000000000000000000000000000000000000610601565b915060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156104a857600080fd5b505afa1580156104bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e09190610691565b50505091505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561054e57600080fd5b505afa158015610562573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061058691906106e9565b90506105b382827f0000000000000000000000000000000000000000000000000000000000000000610601565b9150816105e460ff7f000000000000000000000000000000000000000000000000000000000000000016600a61086f565b6105ee9086610937565b6105f8919061077f565b94505050505090565b60008160ff168360ff16101561063a5761061b83836109f3565b6106299060ff16600a61086f565b6106339085610937565b905061066d565b8160ff168360ff16111561066a5761065282846109f3565b6106609060ff16600a61086f565b610633908561077f565b50825b9392505050565b60006020828403121561068657600080fd5b813561066d81610a45565b600080600080600060a086880312156106a957600080fd5b85516106b481610a45565b8095505060208601519350604086015192506060860151915060808601516106db81610a45565b809150509295509295909350565b6000602082840312156106fb57600080fd5b815160ff8116811461066d57600080fd5b600060208083528351808285015260005b818110156107395785810183015185820160400152820161071d565b8181111561074b576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000826107b5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561080957610809610a16565b500590565b600181815b8085111561086757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561084d5761084d610a16565b8085161561085a57918102915b93841c9390800290610813565b509250929050565b600061066d838360008261088557506001610931565b8161089257506000610931565b81600181146108a857600281146108b2576108ce565b6001915050610931565b60ff8411156108c3576108c3610a16565b50506001821b610931565b5060208310610133831016604e8410600b84101617156108f1575081810a610931565b6108fb838361080e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561092d5761092d610a16565b0290505b92915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561097857610978610a16565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156109b3576109b3610a16565b600087129250878205871284841616156109cf576109cf610a16565b878505871281841616156109e5576109e5610a16565b505050929093029392505050565b600060ff821660ff841680821015610a0d57610a0d610a16565b90039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b69ffffffffffffffffffff81168114610a5d57600080fd5b5056fea164736f6c6343000806000a", -} - -var DerivedPriceFeedABI = DerivedPriceFeedMetaData.ABI - -var DerivedPriceFeedBin = DerivedPriceFeedMetaData.Bin - -func DeployDerivedPriceFeed(auth *bind.TransactOpts, backend bind.ContractBackend, _base common.Address, _quote common.Address, _decimals uint8) (common.Address, *types.Transaction, *DerivedPriceFeed, error) { - parsed, err := DerivedPriceFeedMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DerivedPriceFeedBin), backend, _base, _quote, _decimals) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &DerivedPriceFeed{DerivedPriceFeedCaller: DerivedPriceFeedCaller{contract: contract}, DerivedPriceFeedTransactor: DerivedPriceFeedTransactor{contract: contract}, DerivedPriceFeedFilterer: DerivedPriceFeedFilterer{contract: contract}}, nil -} - -type DerivedPriceFeed struct { - address common.Address - abi abi.ABI - DerivedPriceFeedCaller - DerivedPriceFeedTransactor - DerivedPriceFeedFilterer -} - -type DerivedPriceFeedCaller struct { - contract *bind.BoundContract -} - -type DerivedPriceFeedTransactor struct { - contract *bind.BoundContract -} - -type DerivedPriceFeedFilterer struct { - contract *bind.BoundContract -} - -type DerivedPriceFeedSession struct { - Contract *DerivedPriceFeed - CallOpts bind.CallOpts - TransactOpts bind.TransactOpts -} - -type DerivedPriceFeedCallerSession struct { - Contract *DerivedPriceFeedCaller - CallOpts bind.CallOpts -} - -type DerivedPriceFeedTransactorSession struct { - Contract *DerivedPriceFeedTransactor - TransactOpts bind.TransactOpts -} - -type DerivedPriceFeedRaw struct { - Contract *DerivedPriceFeed -} - -type DerivedPriceFeedCallerRaw struct { - Contract *DerivedPriceFeedCaller -} - -type DerivedPriceFeedTransactorRaw struct { - Contract *DerivedPriceFeedTransactor -} - -func NewDerivedPriceFeed(address common.Address, backend bind.ContractBackend) (*DerivedPriceFeed, error) { - abi, err := abi.JSON(strings.NewReader(DerivedPriceFeedABI)) - if err != nil { - return nil, err - } - contract, err := bindDerivedPriceFeed(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &DerivedPriceFeed{address: address, abi: abi, DerivedPriceFeedCaller: DerivedPriceFeedCaller{contract: contract}, DerivedPriceFeedTransactor: DerivedPriceFeedTransactor{contract: contract}, DerivedPriceFeedFilterer: DerivedPriceFeedFilterer{contract: contract}}, nil -} - -func NewDerivedPriceFeedCaller(address common.Address, caller bind.ContractCaller) (*DerivedPriceFeedCaller, error) { - contract, err := bindDerivedPriceFeed(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &DerivedPriceFeedCaller{contract: contract}, nil -} - -func NewDerivedPriceFeedTransactor(address common.Address, transactor bind.ContractTransactor) (*DerivedPriceFeedTransactor, error) { - contract, err := bindDerivedPriceFeed(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &DerivedPriceFeedTransactor{contract: contract}, nil -} - -func NewDerivedPriceFeedFilterer(address common.Address, filterer bind.ContractFilterer) (*DerivedPriceFeedFilterer, error) { - contract, err := bindDerivedPriceFeed(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &DerivedPriceFeedFilterer{contract: contract}, nil -} - -func bindDerivedPriceFeed(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := DerivedPriceFeedMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -func (_DerivedPriceFeed *DerivedPriceFeedRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DerivedPriceFeed.Contract.DerivedPriceFeedCaller.contract.Call(opts, result, method, params...) -} - -func (_DerivedPriceFeed *DerivedPriceFeedRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DerivedPriceFeed.Contract.DerivedPriceFeedTransactor.contract.Transfer(opts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DerivedPriceFeed.Contract.DerivedPriceFeedTransactor.contract.Transact(opts, method, params...) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DerivedPriceFeed.Contract.contract.Call(opts, result, method, params...) -} - -func (_DerivedPriceFeed *DerivedPriceFeedTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DerivedPriceFeed.Contract.contract.Transfer(opts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DerivedPriceFeed.Contract.contract.Transact(opts, method, params...) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) BASE(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "BASE") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) BASE() (common.Address, error) { - return _DerivedPriceFeed.Contract.BASE(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) BASE() (common.Address, error) { - return _DerivedPriceFeed.Contract.BASE(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) DECIMALS(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "DECIMALS") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) DECIMALS() (uint8, error) { - return _DerivedPriceFeed.Contract.DECIMALS(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) DECIMALS() (uint8, error) { - return _DerivedPriceFeed.Contract.DECIMALS(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) QUOTE(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "QUOTE") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) QUOTE() (common.Address, error) { - return _DerivedPriceFeed.Contract.QUOTE(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) QUOTE() (common.Address, error) { - return _DerivedPriceFeed.Contract.QUOTE(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) Decimals(opts *bind.CallOpts) (uint8, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "decimals") - - if err != nil { - return *new(uint8), err - } - - out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) Decimals() (uint8, error) { - return _DerivedPriceFeed.Contract.Decimals(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) Decimals() (uint8, error) { - return _DerivedPriceFeed.Contract.Decimals(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) Description(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "description") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) Description() (string, error) { - return _DerivedPriceFeed.Contract.Description(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) Description() (string, error) { - return _DerivedPriceFeed.Contract.Description(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) GetRoundData(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, *big.Int, *big.Int, *big.Int, *big.Int, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "getRoundData", arg0) - - if err != nil { - return *new(*big.Int), *new(*big.Int), *new(*big.Int), *new(*big.Int), *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - out2 := *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - out3 := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - out4 := *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) - - return out0, out1, out2, out3, out4, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) GetRoundData(arg0 *big.Int) (*big.Int, *big.Int, *big.Int, *big.Int, *big.Int, error) { - return _DerivedPriceFeed.Contract.GetRoundData(&_DerivedPriceFeed.CallOpts, arg0) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) GetRoundData(arg0 *big.Int) (*big.Int, *big.Int, *big.Int, *big.Int, *big.Int, error) { - return _DerivedPriceFeed.Contract.GetRoundData(&_DerivedPriceFeed.CallOpts, arg0) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) LatestRoundData(opts *bind.CallOpts) (LatestRoundData, - - error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "latestRoundData") - - outstruct := new(LatestRoundData) - if err != nil { - return *outstruct, err - } - - outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - outstruct.Answer = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) - - return *outstruct, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) LatestRoundData() (LatestRoundData, - - error) { - return _DerivedPriceFeed.Contract.LatestRoundData(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) LatestRoundData() (LatestRoundData, - - error) { - return _DerivedPriceFeed.Contract.LatestRoundData(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCaller) Version(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _DerivedPriceFeed.contract.Call(opts, &out, "version") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_DerivedPriceFeed *DerivedPriceFeedSession) Version() (*big.Int, error) { - return _DerivedPriceFeed.Contract.Version(&_DerivedPriceFeed.CallOpts) -} - -func (_DerivedPriceFeed *DerivedPriceFeedCallerSession) Version() (*big.Int, error) { - return _DerivedPriceFeed.Contract.Version(&_DerivedPriceFeed.CallOpts) -} - -type LatestRoundData struct { - RoundId *big.Int - Answer *big.Int - StartedAt *big.Int - UpdatedAt *big.Int - AnsweredInRound *big.Int -} - -func (_DerivedPriceFeed *DerivedPriceFeed) Address() common.Address { - return _DerivedPriceFeed.address -} - -type DerivedPriceFeedInterface interface { - BASE(opts *bind.CallOpts) (common.Address, error) - - DECIMALS(opts *bind.CallOpts) (uint8, error) - - QUOTE(opts *bind.CallOpts) (common.Address, error) - - Decimals(opts *bind.CallOpts) (uint8, error) - - Description(opts *bind.CallOpts) (string, error) - - GetRoundData(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, *big.Int, *big.Int, *big.Int, *big.Int, error) - - LatestRoundData(opts *bind.CallOpts) (LatestRoundData, - - error) - - Version(opts *bind.CallOpts) (*big.Int, error) - - Address() common.Address -} diff --git a/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1/i_keeper_registry_master_wrapper_2_1.go b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1/i_keeper_registry_master_wrapper_2_1.go index c43f32103de..640e871c084 100644 --- a/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1/i_keeper_registry_master_wrapper_2_1.go +++ b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1/i_keeper_registry_master_wrapper_2_1.go @@ -75,7 +75,7 @@ type KeeperRegistryBase21UpkeepInfo struct { } var IKeeperRegistryMasterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkNativeFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMode\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structKeeperRegistryBase2_1.State\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structKeeperRegistryBase2_1.OnchainConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structKeeperRegistryBase2_1.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CheckDataExceedsLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfFaultyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectNumberOfSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpkeepPrivilegeManager\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReentrantCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryPaused\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RepeatedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOracles\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"AdminPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"InsufficientFundsUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"PayeesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"ReorgedUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"StaleUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepOffchainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalPayment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasOverhead\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"privilegeConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepPrivilegeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"UpkeepTriggerConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"executeCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"upkeepFailureReason\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fallbackTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"getAdminPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAutomationForwarderLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFastGasFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkNativeFeedAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLogGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMode\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerPerformByteGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerSignerGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getSignerInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"totalPremium\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"latestConfigBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"latestConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"latestEpoch\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"internalType\":\"structKeeperRegistryBase2_1.State\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structKeeperRegistryBase2_1.OnchainConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getTransmitterInfo\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"lastCollected\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getTriggerType\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"performGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"lastPerformedBlockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structKeeperRegistryBase2_1.UpkeepInfo\",\"name\":\"upkeepInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepPrivilegeConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"}],\"name\":\"getUpkeepTriggerConfig\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"onchainConfigBytes\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxCheckDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxRevertDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"registrars\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"upkeepPrivilegeManager\",\"type\":\"address\"}],\"internalType\":\"structKeeperRegistryBase2_1.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setPayees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"setUpkeepCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"name\":\"setUpkeepOffchainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepPrivilegeConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"simulatePerformUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } var IKeeperRegistryMasterABI = IKeeperRegistryMasterMetaData.ABI @@ -196,6 +196,108 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorRaw) Transact(opts return _IKeeperRegistryMaster.Contract.contract.Transact(opts, method, params...) } +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + var out []interface{} + err := _IKeeperRegistryMaster.contract.Call(opts, &out, "checkCallback", id, values, extraData) + + outstruct := new(CheckCallback) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IKeeperRegistryMaster.Contract.CheckCallback(&_IKeeperRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCallerSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IKeeperRegistryMaster.Contract.CheckCallback(&_IKeeperRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) CheckUpkeep(opts *bind.CallOpts, id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + var out []interface{} + err := _IKeeperRegistryMaster.contract.Call(opts, &out, "checkUpkeep", id, triggerData) + + outstruct := new(CheckUpkeep) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.GasLimit = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FastGasWei = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.LinkNative = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IKeeperRegistryMaster.Contract.CheckUpkeep(&_IKeeperRegistryMaster.CallOpts, id, triggerData) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCallerSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IKeeperRegistryMaster.Contract.CheckUpkeep(&_IKeeperRegistryMaster.CallOpts, id, triggerData) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) CheckUpkeep0(opts *bind.CallOpts, id *big.Int) (CheckUpkeep0, + + error) { + var out []interface{} + err := _IKeeperRegistryMaster.contract.Call(opts, &out, "checkUpkeep0", id) + + outstruct := new(CheckUpkeep0) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.GasLimit = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FastGasWei = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.LinkNative = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IKeeperRegistryMaster.Contract.CheckUpkeep0(&_IKeeperRegistryMaster.CallOpts, id) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCallerSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IKeeperRegistryMaster.Contract.CheckUpkeep0(&_IKeeperRegistryMaster.CallOpts, id) +} + func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _IKeeperRegistryMaster.contract.Call(opts, &out, "fallbackTo") @@ -904,6 +1006,36 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMasterCallerSession) Owner() (commo return _IKeeperRegistryMaster.Contract.Owner(&_IKeeperRegistryMaster.CallOpts) } +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) SimulatePerformUpkeep(opts *bind.CallOpts, id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + var out []interface{} + err := _IKeeperRegistryMaster.contract.Call(opts, &out, "simulatePerformUpkeep", id, performData) + + outstruct := new(SimulatePerformUpkeep) + if err != nil { + return *outstruct, err + } + + outstruct.Success = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.GasUsed = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IKeeperRegistryMaster.Contract.SimulatePerformUpkeep(&_IKeeperRegistryMaster.CallOpts, id, performData) +} + +func (_IKeeperRegistryMaster *IKeeperRegistryMasterCallerSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IKeeperRegistryMaster.Contract.SimulatePerformUpkeep(&_IKeeperRegistryMaster.CallOpts, id, performData) +} + func (_IKeeperRegistryMaster *IKeeperRegistryMasterCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { var out []interface{} err := _IKeeperRegistryMaster.contract.Call(opts, &out, "typeAndVersion") @@ -1030,42 +1162,6 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) CancelUpke return _IKeeperRegistryMaster.Contract.CancelUpkeep(&_IKeeperRegistryMaster.TransactOpts, id) } -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.contract.Transact(opts, "checkCallback", id, values, extraData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckCallback(&_IKeeperRegistryMaster.TransactOpts, id, values, extraData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckCallback(&_IKeeperRegistryMaster.TransactOpts, id, values, extraData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.contract.Transact(opts, "checkUpkeep", id, triggerData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckUpkeep(&_IKeeperRegistryMaster.TransactOpts, id, triggerData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckUpkeep(&_IKeeperRegistryMaster.TransactOpts, id, triggerData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { - return _IKeeperRegistryMaster.contract.Transact(opts, "checkUpkeep0", id) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckUpkeep0(&_IKeeperRegistryMaster.TransactOpts, id) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.CheckUpkeep0(&_IKeeperRegistryMaster.TransactOpts, id) -} - func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { return _IKeeperRegistryMaster.contract.Transact(opts, "executeCallback", id, payload) } @@ -1294,18 +1390,6 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) SetUpkeepT return _IKeeperRegistryMaster.Contract.SetUpkeepTriggerConfig(&_IKeeperRegistryMaster.TransactOpts, id, triggerConfig) } -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.contract.Transact(opts, "simulatePerformUpkeep", id, performData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.SimulatePerformUpkeep(&_IKeeperRegistryMaster.TransactOpts, id, performData) -} - -func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactorSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { - return _IKeeperRegistryMaster.Contract.SimulatePerformUpkeep(&_IKeeperRegistryMaster.TransactOpts, id, performData) -} - func (_IKeeperRegistryMaster *IKeeperRegistryMasterTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _IKeeperRegistryMaster.contract.Transact(opts, "transferOwnership", to) } @@ -5726,6 +5810,30 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMasterFilterer) ParseUpkeepUnpaused return event, nil } +type CheckCallback struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int +} +type CheckUpkeep struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int + GasLimit *big.Int + FastGasWei *big.Int + LinkNative *big.Int +} +type CheckUpkeep0 struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int + GasLimit *big.Int + FastGasWei *big.Int + LinkNative *big.Int +} type GetSignerInfo struct { Active bool Index uint8 @@ -5754,6 +5862,10 @@ type LatestConfigDigestAndEpoch struct { ConfigDigest [32]byte Epoch uint32 } +type SimulatePerformUpkeep struct { + Success bool + GasUsed *big.Int +} func (_IKeeperRegistryMaster *IKeeperRegistryMaster) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { @@ -5966,6 +6078,18 @@ func (_IKeeperRegistryMaster *IKeeperRegistryMaster) Address() common.Address { } type IKeeperRegistryMasterInterface interface { + CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) + + CheckUpkeep(opts *bind.CallOpts, id *big.Int, triggerData []byte) (CheckUpkeep, + + error) + + CheckUpkeep0(opts *bind.CallOpts, id *big.Int) (CheckUpkeep0, + + error) + FallbackTo(opts *bind.CallOpts) (common.Address, error) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) @@ -6036,6 +6160,10 @@ type IKeeperRegistryMasterInterface interface { Owner(opts *bind.CallOpts) (common.Address, error) + SimulatePerformUpkeep(opts *bind.CallOpts, id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) + TypeAndVersion(opts *bind.CallOpts) (string, error) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) @@ -6052,12 +6180,6 @@ type IKeeperRegistryMasterInterface interface { CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) - - CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) - - CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) - ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) @@ -6096,8 +6218,6 @@ type IKeeperRegistryMasterInterface interface { SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) - SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) diff --git a/integration-tests/contracts/ethereum/KeeperConsumerPerformance.go b/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go similarity index 57% rename from integration-tests/contracts/ethereum/KeeperConsumerPerformance.go rename to core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go index 23cbef7c2a3..0e1876ce0a2 100644 --- a/integration-tests/contracts/ethereum/KeeperConsumerPerformance.go +++ b/core/gethwrappers/generated/keeper_consumer_performance_wrapper/keeper_consumer_performance_wrapper.go @@ -1,10 +1,11 @@ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. -package ethereum +package keeper_consumer_performance_wrapper import ( "errors" + "fmt" "math/big" "strings" @@ -14,9 +15,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" ) -// Reference imports to suppress errors if they are not otherwise used. var ( _ = errors.New _ = big.NewInt @@ -26,23 +27,18 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription + _ = abi.ConvertType ) -// KeeperConsumerPerformanceMetaData contains all meta data concerning the KeeperConsumerPerformance contract. var KeeperConsumerPerformanceMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_averageEligibilityCadence\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_checkGasToBurn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_performGasToBurn\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"eligible\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialCall\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nextEligible\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"averageEligibilityCadence\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkEligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCountPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialCall\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextEligible\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setCheckGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newTestRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_newAverageEligibilityCadence\",\"type\":\"uint256\"}],\"name\":\"setSpread\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6080604052600080556000600155600060075534801561001e57600080fd5b506040516105f03803806105f08339818101604052608081101561004157600080fd5b5080516020820151604083015160609093015160029290925560035560049190915560055561057b806100756000396000f3fe608060405234801561001057600080fd5b50600436106100e05760003560e01c80637145f11b116100875780637145f11b146102b05780637f407edf146102e1578063926f086e14610304578063a9a4c57c1461030c578063b30566b414610314578063c228a98e1461031c578063d826f88f14610324578063e303666f1461032c576100e0565b806306661abd146100e557806313bda75b146100ff5780632555d2cf1461011e5780632ff3617d1461013b5780634585e33b14610143578063523d9b8a146101b15780636250a13a146101b95780636e04ff0d146101c1575b600080fd5b6100ed610334565b60408051918252519081900360200190f35b61011c6004803603602081101561011557600080fd5b503561033a565b005b61011c6004803603602081101561013457600080fd5b503561033f565b6100ed610344565b61011c6004803603602081101561015957600080fd5b810190602081018135600160201b81111561017357600080fd5b82018360208201111561018557600080fd5b803590602001918460018302840111600160201b831117156101a657600080fd5b50909250905061034a565b6100ed610425565b6100ed61042b565b61022f600480360360208110156101d757600080fd5b810190602081018135600160201b8111156101f157600080fd5b82018360208201111561020357600080fd5b803590602001918460018302840111600160201b8311171561022457600080fd5b509092509050610431565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561027457818101518382015260200161025c565b50505050905090810190601f1680156102a15780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b6102cd600480360360208110156102c657600080fd5b503561049f565b604080519115158252519081900360200190f35b61011c600480360360408110156102f757600080fd5b50803590602001356104b4565b6100ed6104bf565b6100ed6104c5565b6100ed6104cb565b6102cd6104d1565b61011c6104e0565b6100ed6104ea565b60075481565b600455565b600555565b60045481565b60005a905060006103596104f0565b60005460015460408051841515815232602082015280820193909352606083019190915243608083018190529051929350917fbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc09181900360a00190a1816103bf57600080fd5b6000546103cc5760008190555b6003546002026103da610514565b816103e157fe5b068101600190810181556007805490910190555b6005545a8403101561041e5743406000908152600660205260409020805460ff191690556103f5565b5050505050565b60015481565b60025481565b6000606060005a905060005b6004545a8303101561046d578080156104665750434060009081526006602052604090205460ff165b905061043d565b6104756104f0565b60408051921515602080850191909152815180850390910181529281019052969095509350505050565b60066020526000908152604090205460ff1681565b600291909155600355565b60005481565b60035481565b60055481565b60006104db6104f0565b905090565b6000808055600755565b60075490565b6000805415806104db575060025460005443031080156104db575050600154431190565b604080516000194301406020808301919091523082840152825180830384018152606090920190925280519101209056fea2646970667358221220e233009b46ad9b01fb692930a06d8a04abee3578625455b4761ede5e8ae7489e64736f6c63430007060033", + Bin: "0x6080604052600080556000600155600060075534801561001e57600080fd5b5060405161070438038061070483398101604081905261003d91610054565b60029390935560039190915560045560055561008a565b6000806000806080858703121561006a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b61066b806100996000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80637145f11b11610097578063b30566b411610066578063b30566b4146101f6578063c228a98e146101ff578063d826f88f14610207578063e303666f1461021457600080fd5b80637145f11b146101985780637f407edf146101cb578063926f086e146101e4578063a9a4c57c146101ed57600080fd5b80634585e33b116100d35780634585e33b14610152578063523d9b8a146101655780636250a13a1461016e5780636e04ff0d1461017757600080fd5b806306661abd1461010557806313bda75b146101215780632555d2cf146101365780632ff3617d14610149575b600080fd5b61010e60075481565b6040519081526020015b60405180910390f35b61013461012f366004610430565b600455565b005b610134610144366004610430565b600555565b61010e60045481565b610134610160366004610449565b61021c565b61010e60015481565b61010e60025481565b61018a610185366004610449565b610342565b6040516101189291906104bb565b6101bb6101a6366004610430565b60066020526000908152604090205460ff1681565b6040519015158152602001610118565b6101346101d9366004610531565b600291909155600355565b61010e60005481565b61010e60035481565b61010e60055481565b6101bb6103b7565b6101346000808055600755565b60075461010e565b60005a9050600061022b6103c6565b60005460015460408051841515815232602082015290810192909252606082015243608082018190529192507fbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc09060a00160405180910390a18161028e57600080fd5b60005460000361029e5760008190555b6003546102ac906002610582565b6102b46103f2565b6102be91906105bf565b6102c890826105fa565b6102d39060016105fa565b600155600780549060006102e683610613565b91905055505b6005545a6102fa908561064b565b101561033b574340600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556102ec565b5050505050565b6000606060005a905060005b6004545a61035c908461064b565b10156103865780801561037f5750434060009081526006602052604090205460ff165b905061034e565b61038e6103c6565b604080518315156020820152016040516020818303038152906040529350935050509250929050565b60006103c16103c6565b905090565b6000805415806103c157506002546000546103e1904361064b565b1080156103c1575050600154431190565b60006103ff60014361064b565b604080519140602083015230908201526060016040516020818303038152906040528051906020012060001c905090565b60006020828403121561044257600080fd5b5035919050565b6000806020838503121561045c57600080fd5b823567ffffffffffffffff8082111561047457600080fd5b818501915085601f83011261048857600080fd5b81358181111561049757600080fd5b8660208285010111156104a957600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b818110156104f1578581018301518582016060015282016104d5565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b6000806040838503121561054457600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156105ba576105ba610553565b500290565b6000826105f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b8082018082111561060d5761060d610553565b92915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361064457610644610553565b5060010190565b8181038181111561060d5761060d61055356fea164736f6c6343000810000a", } -// KeeperConsumerPerformanceABI is the input ABI used to generate the binding from. -// Deprecated: Use KeeperConsumerPerformanceMetaData.ABI instead. var KeeperConsumerPerformanceABI = KeeperConsumerPerformanceMetaData.ABI -// KeeperConsumerPerformanceBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use KeeperConsumerPerformanceMetaData.Bin instead. var KeeperConsumerPerformanceBin = KeeperConsumerPerformanceMetaData.Bin -// DeployKeeperConsumerPerformance deploys a new Ethereum contract, binding an instance of KeeperConsumerPerformance to it. func DeployKeeperConsumerPerformance(auth *bind.TransactOpts, backend bind.ContractBackend, _testRange *big.Int, _averageEligibilityCadence *big.Int, _checkGasToBurn *big.Int, _performGasToBurn *big.Int) (common.Address, *types.Transaction, *KeeperConsumerPerformance, error) { parsed, err := KeeperConsumerPerformanceMetaData.GetAbi() if err != nil { @@ -59,75 +55,66 @@ func DeployKeeperConsumerPerformance(auth *bind.TransactOpts, backend bind.Contr return address, tx, &KeeperConsumerPerformance{KeeperConsumerPerformanceCaller: KeeperConsumerPerformanceCaller{contract: contract}, KeeperConsumerPerformanceTransactor: KeeperConsumerPerformanceTransactor{contract: contract}, KeeperConsumerPerformanceFilterer: KeeperConsumerPerformanceFilterer{contract: contract}}, nil } -// KeeperConsumerPerformance is an auto generated Go binding around an Ethereum contract. type KeeperConsumerPerformance struct { - KeeperConsumerPerformanceCaller // Read-only binding to the contract - KeeperConsumerPerformanceTransactor // Write-only binding to the contract - KeeperConsumerPerformanceFilterer // Log filterer for contract events + address common.Address + abi abi.ABI + KeeperConsumerPerformanceCaller + KeeperConsumerPerformanceTransactor + KeeperConsumerPerformanceFilterer } -// KeeperConsumerPerformanceCaller is an auto generated read-only Go binding around an Ethereum contract. type KeeperConsumerPerformanceCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls + contract *bind.BoundContract } -// KeeperConsumerPerformanceTransactor is an auto generated write-only Go binding around an Ethereum contract. type KeeperConsumerPerformanceTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls + contract *bind.BoundContract } -// KeeperConsumerPerformanceFilterer is an auto generated log filtering Go binding around an Ethereum contract events. type KeeperConsumerPerformanceFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls + contract *bind.BoundContract } -// KeeperConsumerPerformanceSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. type KeeperConsumerPerformanceSession struct { - Contract *KeeperConsumerPerformance // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session + Contract *KeeperConsumerPerformance + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts } -// KeeperConsumerPerformanceCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. type KeeperConsumerPerformanceCallerSession struct { - Contract *KeeperConsumerPerformanceCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session + Contract *KeeperConsumerPerformanceCaller + CallOpts bind.CallOpts } -// KeeperConsumerPerformanceTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. type KeeperConsumerPerformanceTransactorSession struct { - Contract *KeeperConsumerPerformanceTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session + Contract *KeeperConsumerPerformanceTransactor + TransactOpts bind.TransactOpts } -// KeeperConsumerPerformanceRaw is an auto generated low-level Go binding around an Ethereum contract. type KeeperConsumerPerformanceRaw struct { - Contract *KeeperConsumerPerformance // Generic contract binding to access the raw methods on + Contract *KeeperConsumerPerformance } -// KeeperConsumerPerformanceCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. type KeeperConsumerPerformanceCallerRaw struct { - Contract *KeeperConsumerPerformanceCaller // Generic read-only contract binding to access the raw methods on + Contract *KeeperConsumerPerformanceCaller } -// KeeperConsumerPerformanceTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. type KeeperConsumerPerformanceTransactorRaw struct { - Contract *KeeperConsumerPerformanceTransactor // Generic write-only contract binding to access the raw methods on + Contract *KeeperConsumerPerformanceTransactor } -// NewKeeperConsumerPerformance creates a new instance of KeeperConsumerPerformance, bound to a specific deployed contract. func NewKeeperConsumerPerformance(address common.Address, backend bind.ContractBackend) (*KeeperConsumerPerformance, error) { + abi, err := abi.JSON(strings.NewReader(KeeperConsumerPerformanceABI)) + if err != nil { + return nil, err + } contract, err := bindKeeperConsumerPerformance(address, backend, backend, backend) if err != nil { return nil, err } - return &KeeperConsumerPerformance{KeeperConsumerPerformanceCaller: KeeperConsumerPerformanceCaller{contract: contract}, KeeperConsumerPerformanceTransactor: KeeperConsumerPerformanceTransactor{contract: contract}, KeeperConsumerPerformanceFilterer: KeeperConsumerPerformanceFilterer{contract: contract}}, nil + return &KeeperConsumerPerformance{address: address, abi: abi, KeeperConsumerPerformanceCaller: KeeperConsumerPerformanceCaller{contract: contract}, KeeperConsumerPerformanceTransactor: KeeperConsumerPerformanceTransactor{contract: contract}, KeeperConsumerPerformanceFilterer: KeeperConsumerPerformanceFilterer{contract: contract}}, nil } -// NewKeeperConsumerPerformanceCaller creates a new read-only instance of KeeperConsumerPerformance, bound to a specific deployed contract. func NewKeeperConsumerPerformanceCaller(address common.Address, caller bind.ContractCaller) (*KeeperConsumerPerformanceCaller, error) { contract, err := bindKeeperConsumerPerformance(address, caller, nil, nil) if err != nil { @@ -136,7 +123,6 @@ func NewKeeperConsumerPerformanceCaller(address common.Address, caller bind.Cont return &KeeperConsumerPerformanceCaller{contract: contract}, nil } -// NewKeeperConsumerPerformanceTransactor creates a new write-only instance of KeeperConsumerPerformance, bound to a specific deployed contract. func NewKeeperConsumerPerformanceTransactor(address common.Address, transactor bind.ContractTransactor) (*KeeperConsumerPerformanceTransactor, error) { contract, err := bindKeeperConsumerPerformance(address, nil, transactor, nil) if err != nil { @@ -145,7 +131,6 @@ func NewKeeperConsumerPerformanceTransactor(address common.Address, transactor b return &KeeperConsumerPerformanceTransactor{contract: contract}, nil } -// NewKeeperConsumerPerformanceFilterer creates a new log filterer instance of KeeperConsumerPerformance, bound to a specific deployed contract. func NewKeeperConsumerPerformanceFilterer(address common.Address, filterer bind.ContractFilterer) (*KeeperConsumerPerformanceFilterer, error) { contract, err := bindKeeperConsumerPerformance(address, nil, nil, filterer) if err != nil { @@ -154,56 +139,38 @@ func NewKeeperConsumerPerformanceFilterer(address common.Address, filterer bind. return &KeeperConsumerPerformanceFilterer{contract: contract}, nil } -// bindKeeperConsumerPerformance binds a generic wrapper to an already deployed contract. func bindKeeperConsumerPerformance(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(KeeperConsumerPerformanceABI)) + parsed, err := KeeperConsumerPerformanceMetaData.GetAbi() if err != nil { return nil, err } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _KeeperConsumerPerformance.Contract.KeeperConsumerPerformanceCaller.contract.Call(opts, result, method, params...) } -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.KeeperConsumerPerformanceTransactor.contract.Transfer(opts) } -// Transact invokes the (paid) contract method with params as input values. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.KeeperConsumerPerformanceTransactor.contract.Transact(opts, method, params...) } -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _KeeperConsumerPerformance.Contract.contract.Call(opts, result, method, params...) } -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.contract.Transfer(opts) } -// Transact invokes the (paid) contract method with params as input values. func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.contract.Transact(opts, method, params...) } -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) AverageEligibilityCadence(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "averageEligibilityCadence") @@ -218,23 +185,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) AverageEligib } -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) AverageEligibilityCadence() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.AverageEligibilityCadence(&_KeeperConsumerPerformance.CallOpts) } -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) AverageEligibilityCadence() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.AverageEligibilityCadence(&_KeeperConsumerPerformance.CallOpts) } -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckEligible(opts *bind.CallOpts) (bool, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "checkEligible") @@ -249,23 +207,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckEligible } -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) CheckEligible() (bool, error) { return _KeeperConsumerPerformance.Contract.CheckEligible(&_KeeperConsumerPerformance.CallOpts) } -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) CheckEligible() (bool, error) { return _KeeperConsumerPerformance.Contract.CheckEligible(&_KeeperConsumerPerformance.CallOpts) } -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckGasToBurn(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "checkGasToBurn") @@ -280,23 +229,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckGasToBur } -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) CheckGasToBurn() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.CheckGasToBurn(&_KeeperConsumerPerformance.CallOpts) } -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) CheckGasToBurn() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.CheckGasToBurn(&_KeeperConsumerPerformance.CallOpts) } -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "checkUpkeep", data) @@ -312,23 +252,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) CheckUpkeep(o } -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) CheckUpkeep(data []byte) (bool, []byte, error) { return _KeeperConsumerPerformance.Contract.CheckUpkeep(&_KeeperConsumerPerformance.CallOpts, data) } -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) CheckUpkeep(data []byte) (bool, []byte, error) { return _KeeperConsumerPerformance.Contract.CheckUpkeep(&_KeeperConsumerPerformance.CallOpts, data) } -// Count is a free data retrieval call binding the contract method 0x06661abd. -// -// Solidity: function count() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) Count(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "count") @@ -343,23 +274,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) Count(opts *b } -// Count is a free data retrieval call binding the contract method 0x06661abd. -// -// Solidity: function count() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) Count() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.Count(&_KeeperConsumerPerformance.CallOpts) } -// Count is a free data retrieval call binding the contract method 0x06661abd. -// -// Solidity: function count() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) Count() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.Count(&_KeeperConsumerPerformance.CallOpts) } -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "dummyMap", arg0) @@ -374,23 +296,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) DummyMap(opts } -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) DummyMap(arg0 [32]byte) (bool, error) { return _KeeperConsumerPerformance.Contract.DummyMap(&_KeeperConsumerPerformance.CallOpts, arg0) } -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) DummyMap(arg0 [32]byte) (bool, error) { return _KeeperConsumerPerformance.Contract.DummyMap(&_KeeperConsumerPerformance.CallOpts, arg0) } -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) GetCountPerforms(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "getCountPerforms") @@ -405,23 +318,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) GetCountPerfo } -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) GetCountPerforms() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.GetCountPerforms(&_KeeperConsumerPerformance.CallOpts) } -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) GetCountPerforms() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.GetCountPerforms(&_KeeperConsumerPerformance.CallOpts) } -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) InitialCall(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "initialCall") @@ -436,23 +340,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) InitialCall(o } -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) InitialCall() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.InitialCall(&_KeeperConsumerPerformance.CallOpts) } -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) InitialCall() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.InitialCall(&_KeeperConsumerPerformance.CallOpts) } -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) NextEligible(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "nextEligible") @@ -467,23 +362,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) NextEligible( } -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) NextEligible() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.NextEligible(&_KeeperConsumerPerformance.CallOpts) } -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) NextEligible() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.NextEligible(&_KeeperConsumerPerformance.CallOpts) } -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) PerformGasToBurn(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "performGasToBurn") @@ -498,23 +384,14 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) PerformGasToB } -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) PerformGasToBurn() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.PerformGasToBurn(&_KeeperConsumerPerformance.CallOpts) } -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) PerformGasToBurn() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.PerformGasToBurn(&_KeeperConsumerPerformance.CallOpts) } -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) TestRange(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _KeeperConsumerPerformance.contract.Call(opts, &out, "testRange") @@ -529,147 +406,92 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCaller) TestRange(opt } -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) TestRange() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.TestRange(&_KeeperConsumerPerformance.CallOpts) } -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceCallerSession) TestRange() (*big.Int, error) { return _KeeperConsumerPerformance.Contract.TestRange(&_KeeperConsumerPerformance.CallOpts) } -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes data) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactor) PerformUpkeep(opts *bind.TransactOpts, data []byte) (*types.Transaction, error) { return _KeeperConsumerPerformance.contract.Transact(opts, "performUpkeep", data) } -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes data) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) PerformUpkeep(data []byte) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.PerformUpkeep(&_KeeperConsumerPerformance.TransactOpts, data) } -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes data) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorSession) PerformUpkeep(data []byte) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.PerformUpkeep(&_KeeperConsumerPerformance.TransactOpts, data) } -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { return _KeeperConsumerPerformance.contract.Transact(opts, "reset") } -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) Reset() (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.Reset(&_KeeperConsumerPerformance.TransactOpts) } -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorSession) Reset() (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.Reset(&_KeeperConsumerPerformance.TransactOpts) } -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactor) SetCheckGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.contract.Transact(opts, "setCheckGasToBurn", value) } -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) SetCheckGasToBurn(value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetCheckGasToBurn(&_KeeperConsumerPerformance.TransactOpts, value) } -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorSession) SetCheckGasToBurn(value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetCheckGasToBurn(&_KeeperConsumerPerformance.TransactOpts, value) } -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactor) SetPerformGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.contract.Transact(opts, "setPerformGasToBurn", value) } -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) SetPerformGasToBurn(value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetPerformGasToBurn(&_KeeperConsumerPerformance.TransactOpts, value) } -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorSession) SetPerformGasToBurn(value *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetPerformGasToBurn(&_KeeperConsumerPerformance.TransactOpts, value) } -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactor) SetSpread(opts *bind.TransactOpts, _newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.contract.Transact(opts, "setSpread", _newTestRange, _newAverageEligibilityCadence) } -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceSession) SetSpread(_newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetSpread(&_KeeperConsumerPerformance.TransactOpts, _newTestRange, _newAverageEligibilityCadence) } -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() func (_KeeperConsumerPerformance *KeeperConsumerPerformanceTransactorSession) SetSpread(_newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { return _KeeperConsumerPerformance.Contract.SetSpread(&_KeeperConsumerPerformance.TransactOpts, _newTestRange, _newAverageEligibilityCadence) } -// KeeperConsumerPerformancePerformingUpkeepIterator is returned from FilterPerformingUpkeep and is used to iterate over the raw logs and unpacked data for PerformingUpkeep events raised by the KeeperConsumerPerformance contract. type KeeperConsumerPerformancePerformingUpkeepIterator struct { - Event *KeeperConsumerPerformancePerformingUpkeep // Event containing the contract specifics and raw log + Event *KeeperConsumerPerformancePerformingUpkeep - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data + contract *bind.BoundContract + event string - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration + logs chan types.Log + sub ethereum.Subscription + done bool + fail error } -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. func (it *KeeperConsumerPerformancePerformingUpkeepIterator) Next() bool { - // If the iterator failed, stop iterating + if it.fail != nil { return false } - // If the iterator completed, deliver directly whatever's available + if it.done { select { case log := <-it.logs: @@ -685,7 +507,7 @@ func (it *KeeperConsumerPerformancePerformingUpkeepIterator) Next() bool { return false } } - // Iterator still in progress, wait for either a data or an error event + select { case log := <-it.logs: it.Event = new(KeeperConsumerPerformancePerformingUpkeep) @@ -703,31 +525,24 @@ func (it *KeeperConsumerPerformancePerformingUpkeepIterator) Next() bool { } } -// Error returns any retrieval or parsing error occurred during filtering. func (it *KeeperConsumerPerformancePerformingUpkeepIterator) Error() error { return it.fail } -// Close terminates the iteration process, releasing any pending underlying -// resources. func (it *KeeperConsumerPerformancePerformingUpkeepIterator) Close() error { it.sub.Unsubscribe() return nil } -// KeeperConsumerPerformancePerformingUpkeep represents a PerformingUpkeep event raised by the KeeperConsumerPerformance contract. type KeeperConsumerPerformancePerformingUpkeep struct { Eligible bool From common.Address InitialCall *big.Int NextEligible *big.Int BlockNumber *big.Int - Raw types.Log // Blockchain specific contextual infos + Raw types.Log } -// FilterPerformingUpkeep is a free log retrieval operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) FilterPerformingUpkeep(opts *bind.FilterOpts) (*KeeperConsumerPerformancePerformingUpkeepIterator, error) { logs, sub, err := _KeeperConsumerPerformance.contract.FilterLogs(opts, "PerformingUpkeep") @@ -737,9 +552,6 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) FilterPerfo return &KeeperConsumerPerformancePerformingUpkeepIterator{contract: _KeeperConsumerPerformance.contract, event: "PerformingUpkeep", logs: logs, sub: sub}, nil } -// WatchPerformingUpkeep is a free log subscription operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *KeeperConsumerPerformancePerformingUpkeep) (event.Subscription, error) { logs, sub, err := _KeeperConsumerPerformance.contract.WatchLogs(opts, "PerformingUpkeep") @@ -751,7 +563,7 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) WatchPerfor for { select { case log := <-logs: - // New log arrived, parse the event and forward to the user + event := new(KeeperConsumerPerformancePerformingUpkeep) if err := _KeeperConsumerPerformance.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { return err @@ -774,9 +586,6 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) WatchPerfor }), nil } -// ParsePerformingUpkeep is a log parse operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) ParsePerformingUpkeep(log types.Log) (*KeeperConsumerPerformancePerformingUpkeep, error) { event := new(KeeperConsumerPerformancePerformingUpkeep) if err := _KeeperConsumerPerformance.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { @@ -785,3 +594,65 @@ func (_KeeperConsumerPerformance *KeeperConsumerPerformanceFilterer) ParsePerfor event.Raw = log return event, nil } + +func (_KeeperConsumerPerformance *KeeperConsumerPerformance) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _KeeperConsumerPerformance.abi.Events["PerformingUpkeep"].ID: + return _KeeperConsumerPerformance.ParsePerformingUpkeep(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (KeeperConsumerPerformancePerformingUpkeep) Topic() common.Hash { + return common.HexToHash("0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0") +} + +func (_KeeperConsumerPerformance *KeeperConsumerPerformance) Address() common.Address { + return _KeeperConsumerPerformance.address +} + +type KeeperConsumerPerformanceInterface interface { + AverageEligibilityCadence(opts *bind.CallOpts) (*big.Int, error) + + CheckEligible(opts *bind.CallOpts) (bool, error) + + CheckGasToBurn(opts *bind.CallOpts) (*big.Int, error) + + CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) + + Count(opts *bind.CallOpts) (*big.Int, error) + + DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) + + GetCountPerforms(opts *bind.CallOpts) (*big.Int, error) + + InitialCall(opts *bind.CallOpts) (*big.Int, error) + + NextEligible(opts *bind.CallOpts) (*big.Int, error) + + PerformGasToBurn(opts *bind.CallOpts) (*big.Int, error) + + TestRange(opts *bind.CallOpts) (*big.Int, error) + + PerformUpkeep(opts *bind.TransactOpts, data []byte) (*types.Transaction, error) + + Reset(opts *bind.TransactOpts) (*types.Transaction, error) + + SetCheckGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) + + SetPerformGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) + + SetSpread(opts *bind.TransactOpts, _newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) + + FilterPerformingUpkeep(opts *bind.FilterOpts) (*KeeperConsumerPerformancePerformingUpkeepIterator, error) + + WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *KeeperConsumerPerformancePerformingUpkeep) (event.Subscription, error) + + ParsePerformingUpkeep(log types.Log) (*KeeperConsumerPerformancePerformingUpkeep, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go new file mode 100644 index 00000000000..896927f9e6d --- /dev/null +++ b/core/gethwrappers/generated/keeper_consumer_wrapper/keeper_consumer_wrapper.go @@ -0,0 +1,303 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_consumer_wrapper + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var KeeperConsumerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"updateInterval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastTimeStamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b5060405161036c38038061036c83398101604081905261002f9161003f565b6080524260015560008055610058565b60006020828403121561005157600080fd5b5051919050565b6080516102fa610072600039600060cc01526102fa6000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806361bc221a1161005057806361bc221a1461009d5780636e04ff0d146100a6578063947a36fb146100c757600080fd5b80633f3b3b271461006c5780634585e33b14610088575b600080fd5b61007560015481565b6040519081526020015b60405180910390f35b61009b6100963660046101c5565b6100ee565b005b61007560005481565b6100b96100b43660046101c5565b610103565b60405161007f929190610237565b6100757f000000000000000000000000000000000000000000000000000000000000000081565b6000546100fc9060016102ad565b6000555050565b6000606061010f610157565b6001848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b32156101c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f6f6e6c7920666f722073696d756c61746564206261636b656e64000000000000604482015260640160405180910390fd5b565b600080602083850312156101d857600080fd5b823567ffffffffffffffff808211156101f057600080fd5b818501915085601f83011261020457600080fd5b81358181111561021357600080fd5b86602082850101111561022557600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b8181101561026d57858101830151858201606001528201610251565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b808201808211156102e7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a", +} + +var KeeperConsumerABI = KeeperConsumerMetaData.ABI + +var KeeperConsumerBin = KeeperConsumerMetaData.Bin + +func DeployKeeperConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, updateInterval *big.Int) (common.Address, *types.Transaction, *KeeperConsumer, error) { + parsed, err := KeeperConsumerMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(KeeperConsumerBin), backend, updateInterval) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &KeeperConsumer{KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil +} + +type KeeperConsumer struct { + address common.Address + abi abi.ABI + KeeperConsumerCaller + KeeperConsumerTransactor + KeeperConsumerFilterer +} + +type KeeperConsumerCaller struct { + contract *bind.BoundContract +} + +type KeeperConsumerTransactor struct { + contract *bind.BoundContract +} + +type KeeperConsumerFilterer struct { + contract *bind.BoundContract +} + +type KeeperConsumerSession struct { + Contract *KeeperConsumer + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type KeeperConsumerCallerSession struct { + Contract *KeeperConsumerCaller + CallOpts bind.CallOpts +} + +type KeeperConsumerTransactorSession struct { + Contract *KeeperConsumerTransactor + TransactOpts bind.TransactOpts +} + +type KeeperConsumerRaw struct { + Contract *KeeperConsumer +} + +type KeeperConsumerCallerRaw struct { + Contract *KeeperConsumerCaller +} + +type KeeperConsumerTransactorRaw struct { + Contract *KeeperConsumerTransactor +} + +func NewKeeperConsumer(address common.Address, backend bind.ContractBackend) (*KeeperConsumer, error) { + abi, err := abi.JSON(strings.NewReader(KeeperConsumerABI)) + if err != nil { + return nil, err + } + contract, err := bindKeeperConsumer(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &KeeperConsumer{address: address, abi: abi, KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil +} + +func NewKeeperConsumerCaller(address common.Address, caller bind.ContractCaller) (*KeeperConsumerCaller, error) { + contract, err := bindKeeperConsumer(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &KeeperConsumerCaller{contract: contract}, nil +} + +func NewKeeperConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*KeeperConsumerTransactor, error) { + contract, err := bindKeeperConsumer(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &KeeperConsumerTransactor{contract: contract}, nil +} + +func NewKeeperConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*KeeperConsumerFilterer, error) { + contract, err := bindKeeperConsumer(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &KeeperConsumerFilterer{contract: contract}, nil +} + +func bindKeeperConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := KeeperConsumerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_KeeperConsumer *KeeperConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _KeeperConsumer.Contract.KeeperConsumerCaller.contract.Call(opts, result, method, params...) +} + +func (_KeeperConsumer *KeeperConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _KeeperConsumer.Contract.KeeperConsumerTransactor.contract.Transfer(opts) +} + +func (_KeeperConsumer *KeeperConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _KeeperConsumer.Contract.KeeperConsumerTransactor.contract.Transact(opts, method, params...) +} + +func (_KeeperConsumer *KeeperConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _KeeperConsumer.Contract.contract.Call(opts, result, method, params...) +} + +func (_KeeperConsumer *KeeperConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _KeeperConsumer.Contract.contract.Transfer(opts) +} + +func (_KeeperConsumer *KeeperConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _KeeperConsumer.Contract.contract.Transact(opts, method, params...) +} + +func (_KeeperConsumer *KeeperConsumerCaller) CheckUpkeep(opts *bind.CallOpts, checkData []byte) (CheckUpkeep, + + error) { + var out []interface{} + err := _KeeperConsumer.contract.Call(opts, &out, "checkUpkeep", checkData) + + outstruct := new(CheckUpkeep) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +func (_KeeperConsumer *KeeperConsumerSession) CheckUpkeep(checkData []byte) (CheckUpkeep, + + error) { + return _KeeperConsumer.Contract.CheckUpkeep(&_KeeperConsumer.CallOpts, checkData) +} + +func (_KeeperConsumer *KeeperConsumerCallerSession) CheckUpkeep(checkData []byte) (CheckUpkeep, + + error) { + return _KeeperConsumer.Contract.CheckUpkeep(&_KeeperConsumer.CallOpts, checkData) +} + +func (_KeeperConsumer *KeeperConsumerCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _KeeperConsumer.contract.Call(opts, &out, "counter") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_KeeperConsumer *KeeperConsumerSession) Counter() (*big.Int, error) { + return _KeeperConsumer.Contract.Counter(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerCallerSession) Counter() (*big.Int, error) { + return _KeeperConsumer.Contract.Counter(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerCaller) Interval(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _KeeperConsumer.contract.Call(opts, &out, "interval") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_KeeperConsumer *KeeperConsumerSession) Interval() (*big.Int, error) { + return _KeeperConsumer.Contract.Interval(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerCallerSession) Interval() (*big.Int, error) { + return _KeeperConsumer.Contract.Interval(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerCaller) LastTimeStamp(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _KeeperConsumer.contract.Call(opts, &out, "lastTimeStamp") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_KeeperConsumer *KeeperConsumerSession) LastTimeStamp() (*big.Int, error) { + return _KeeperConsumer.Contract.LastTimeStamp(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerCallerSession) LastTimeStamp() (*big.Int, error) { + return _KeeperConsumer.Contract.LastTimeStamp(&_KeeperConsumer.CallOpts) +} + +func (_KeeperConsumer *KeeperConsumerTransactor) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) { + return _KeeperConsumer.contract.Transact(opts, "performUpkeep", performData) +} + +func (_KeeperConsumer *KeeperConsumerSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { + return _KeeperConsumer.Contract.PerformUpkeep(&_KeeperConsumer.TransactOpts, performData) +} + +func (_KeeperConsumer *KeeperConsumerTransactorSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { + return _KeeperConsumer.Contract.PerformUpkeep(&_KeeperConsumer.TransactOpts, performData) +} + +type CheckUpkeep struct { + UpkeepNeeded bool + PerformData []byte +} + +func (_KeeperConsumer *KeeperConsumer) Address() common.Address { + return _KeeperConsumer.address +} + +type KeeperConsumerInterface interface { + CheckUpkeep(opts *bind.CallOpts, checkData []byte) (CheckUpkeep, + + error) + + Counter(opts *bind.CallOpts) (*big.Int, error) + + Interval(opts *bind.CallOpts) (*big.Int, error) + + LastTimeStamp(opts *bind.CallOpts) (*big.Int, error) + + PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go b/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go index 07b01aa9e26..6049536df69 100644 --- a/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go +++ b/core/gethwrappers/generated/keeper_registry_logic1_3/keeper_registry_logic1_3.go @@ -47,7 +47,7 @@ type Config struct { var KeeperRegistryLogicMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"enumKeeperRegistryBase1_3.PaymentModel\",\"name\":\"paymentModel\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"registryGasOverhead\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fastGasFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeepersMustTakeTurns\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveKeepers\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"KeepersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"executeGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ARB_NITRO_ORACLE\",\"outputs\":[{\"internalType\":\"contractArbGasInfo\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FAST_GAS_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_ORACLE\",\"outputs\":[{\"internalType\":\"contractOVM_GasPriceOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PAYMENT_MODEL\",\"outputs\":[{\"internalType\":\"enumKeeperRegistryBase1_3.PaymentModel\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REGISTRY_GAS_OVERHEAD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxLinkPayment\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"adjustedGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkEth\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setKeepers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"enumKeeperRegistryBase1_3.MigrationPermission\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101606040527f420000000000000000000000000000000000000f00000000000000000000000060e0526c6c000000000000000000000000610100523480156200004857600080fd5b506040516200594f3803806200594f8339810160408190526200006b916200028f565b84848484843380600081620000c75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000fa57620000fa81620001c6565b5050600160029081556003805460ff19169055869150811115620001225762000122620002fc565b6101208160028111156200013a576200013a620002fc565b60f81b9052506101408490526001600160a01b03831615806200016457506001600160a01b038216155b806200017757506001600160a01b038116155b156200019657604051637138356f60e01b815260040160405180910390fd5b6001600160601b0319606093841b811660805291831b821660a05290911b1660c052506200031295505050505050565b6001600160a01b038116331415620002215760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000be565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028a57600080fd5b919050565b600080600080600060a08688031215620002a857600080fd5b855160038110620002b857600080fd5b60208701519095509350620002d06040870162000272565b9250620002e06060870162000272565b9150620002f06080870162000272565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160f81c6101405161556e620003e16000396000818161028c0152613f1d01526000818161036301528181613f7001526140ec0152600081816102fa0152614124015260008181610329015261405b0152600081816102650152613c510152600081816104010152613d3201526000818161020c01528181610a4601528181610ca30152818161150e0152818161197301528181611c63015281816122730152612306015261556e6000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80638da5cb5b11610104578063b148ab6b116100a2578063c804802211610071578063c804802214610488578063da5c67411461049b578063eb5dcd6c146104ae578063f2fde38b146104c157600080fd5b8063b148ab6b14610436578063b79550be14610449578063b7fdb43614610451578063c41b813a1461046457600080fd5b8063a710b221116100de578063a710b221146103d6578063a72aa27e146103e9578063ad178361146103fc578063b121e1471461042357600080fd5b80638da5cb5b146103925780638e86139b146103b0578063948108f7146103c357600080fd5b8063744bfe611161017c5780638456cb591161014b5780638456cb591461031c578063850cce341461032457806385c1b0ba1461034b5780638811cbe81461035e57600080fd5b8063744bfe61146102d257806379ba5097146102e55780637d9b97e0146102ed5780637f37618e146102f557600080fd5b80633f4ba83a116101b85780633f4ba83a146102585780634584a419146102605780635077b210146102875780635c975abb146102bc57600080fd5b8063187256e8146101df5780631a2af011146101f45780631b6b6d2314610207575b600080fd5b6101f26101ed36600461479c565b6104d4565b005b6101f2610202366004614b30565b610545565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101f2610770565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6102ae7f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161024f565b60035460ff16604051901515815260200161024f565b6101f26102e0366004614b30565b610782565b6101f2610ac9565b6101f2610bcb565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f2610d39565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f26103593660046148b9565b610d49565b6103857f000000000000000000000000000000000000000000000000000000000000000081565b60405161024f9190614fc8565b60005473ffffffffffffffffffffffffffffffffffffffff1661022e565b6101f26103be366004614a66565b611598565b6101f26103d1366004614b76565b6117b6565b6101f26103e4366004614769565b611a4f565b6101f26103f7366004614b53565b611ce7565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f261043136600461474e565b611f20565b6101f2610444366004614afe565b612018565b6101f261223a565b6101f261045f36600461484d565b6123a5565b610477610472366004614b30565b612706565b60405161024f959493929190614eb2565b6101f2610496366004614afe565b612a18565b6102ae6104a93660046147d7565b612d92565b6101f26104bc366004614769565b612f89565b6101f26104cf36600461474e565b6130e8565b6104dc6130fc565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561053c5761053c615308565b02179055505050565b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e08201526106248161317d565b73ffffffffffffffffffffffffffffffffffffffff8216331415610674576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166106c1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff83811691161461076b576000838152600a602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590519091339186917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b505050565b6107786130fc565b61078061322a565b565b73ffffffffffffffffffffffffffffffffffffffff81166107cf576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff9081169584019590955260018401549081169583019590955290930482166060840181905260029091015463ffffffff808216608086015264010000000082041660a085015268010000000000000000810490921660c08401527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e083015233146108e2576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b438160a0015163ffffffff161115610926576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600760205260409020546012546bffffffffffffffffffffffff909116906109549082906151b8565b60125560008481526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016905581516bffffffffffffffffffffffff8416815273ffffffffffffffffffffffffffffffffffffffff86169181019190915285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a26040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015610a8a57600080fd5b505af1158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac291906149f1565b5050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610bd36130fc565b6011546012546bffffffffffffffffffffffff90911690610bf59082906151b8565b601255601180547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b602060405180830381600087803b158015610cfd57600080fd5b505af1158015610d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3591906149f1565b5050565b610d416130fc565b61078061330b565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff166003811115610d8557610d85615308565b14158015610dcd5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff166003811115610dca57610dca615308565b14155b15610e04576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60135473ffffffffffffffffffffffffffffffffffffffff16610e53576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610e8a576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526000808567ffffffffffffffff811115610ee657610ee6615395565b604051908082528060200260200182016040528015610f1957816020015b6060815260200190600190039081610f045790505b50905060008667ffffffffffffffff811115610f3757610f37615395565b604051908082528060200260200182016040528015610fc457816020015b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610f555790505b50905060005b878110156112ce57888882818110610fe457610fe4615366565b6020908102929092013560008181526007845260409081902081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811698840198909852600184015490811694830194909452909204851660608301526002015463ffffffff808216608084015264010000000082041660a083015268010000000000000000810490941660c08201527c010000000000000000000000000000000000000000000000000000000090930460ff16151560e084015297509095506110d290508561317d565b848282815181106110e5576110e5615366565b6020026020010181905250600b6000878152602001908152602001600020805461110e90615228565b80601f016020809104026020016040519081016040528092919081815260200182805461113a90615228565b80156111875780601f1061115c57610100808354040283529160200191611187565b820191906000526020600020905b81548152906001019060200180831161116a57829003601f168201915b505050505083828151811061119e5761119e615366565b602090810291909101015284516111c3906bffffffffffffffffffffffff16856150f8565b60008781526007602090815260408083208381556001810184905560020180547fffffff0000000000000000000000000000000000000000000000000000000000169055600b909152812091955061121b91906142d9565b6000868152600a6020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561125a6005876133cb565b508451604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8916602083015287917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a2806112c68161527c565b915050610fca565b50826012546112dd91906151b8565b6012556040516000906112fa908a908a9085908790602001614d41565b60405160208183030381529060405290508673ffffffffffffffffffffffffffffffffffffffff16638e86139b601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60018b73ffffffffffffffffffffffffffffffffffffffff166348013d7b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113ad57600080fd5b505afa1580156113c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e59190614add565b866040518463ffffffff1660e01b815260040161140493929190614fdb565b60006040518083038186803b15801561141c57600080fd5b505afa158015611430573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114769190810190614aa8565b6040518263ffffffff1660e01b81526004016114929190614e9f565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152602482018890527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb9150604401602060405180830381600087803b15801561155457600080fd5b505af1158015611568573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158c91906149f1565b50505050505050505050565b6002336000908152600c602052604090205460ff1660038111156115be576115be615308565b141580156115f057506003336000908152600c602052604090205460ff1660038111156115ed576115ed615308565b14155b15611627576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080806116378486018661490d565b92509250925060005b83518110156117ae5761171b84828151811061165e5761165e615366565b602002602001015184838151811061167857611678615366565b602002602001015160c0015185848151811061169657611696615366565b6020026020010151608001518685815181106116b4576116b4615366565b6020026020010151606001518786815181106116d2576116d2615366565b6020026020010151600001518787815181106116f0576116f0615366565b602002602001015189888151811061170a5761170a615366565b602002602001015160e001516133e0565b83818151811061172d5761172d615366565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7184838151811061176857611768615366565b60209081029190910181015151604080516bffffffffffffffffffffffff909216825233928201929092520160405180910390a2806117a68161527c565b915050611640565b505050505050565b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e0840152146118c7576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516118d4908390615110565b600084815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601254611928918416906150f8565b6012556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b1580156119cc57600080fd5b505af11580156119e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0491906149f1565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a9c576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16928101929092526001015460ff16151591810191909152903314611b4d576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff80841660009081526008602090815260409091208054909216909155810151601254611b9c916bffffffffffffffffffffffff16906151b8565b60125560208082015160405133815273ffffffffffffffffffffffffffffffffffffffff808616936bffffffffffffffffffffffff90931692908716917f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698910160405180910390a460208101516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff90921660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015611ca957600080fd5b505af1158015611cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce191906149f1565b50505050565b6108fc8163ffffffff161080611d085750600e5463ffffffff908116908216115b15611d3f576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e084015214611e50576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015173ffffffffffffffffffffffffffffffffffffffff163314611ea3576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602090815260409182902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8616908117909155915191825284917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a2505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260096020526040902054163314611f80576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526008602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556009909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e084015214612129576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612186576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060810151600083815260076020908152604080832060010180546bffffffffffffffffffffffff16336c01000000000000000000000000810291909117909155600a90925280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905551909173ffffffffffffffffffffffffffffffffffffffff84169186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b6122426130fc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156122ca57600080fd5b505afa1580156122de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123029190614b17565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb336012548461234f91906151b8565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401610ce3565b6123ad6130fc565b82811415806123bc5750600283105b156123f3576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60045481101561247f5760006004828154811061241557612415615366565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168252600890526040902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550806124778161527c565b9150506123f6565b5060005b838110156126b557600085858381811061249f5761249f615366565b90506020020160208101906124b4919061474e565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600860205260408120805493945092909116908686868181106124f6576124f6615366565b905060200201602081019061250b919061474e565b905073ffffffffffffffffffffffffffffffffffffffff8116158061259e575073ffffffffffffffffffffffffffffffffffffffff82161580159061257c57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561259e575073ffffffffffffffffffffffffffffffffffffffff81811614155b156125d5576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183015460ff1615612614576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905573ffffffffffffffffffffffffffffffffffffffff8181161461269e5782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783555b5050505080806126ad9061527c565b915050612483565b506126c260048585614313565b507f056264c94f28bb06c99d13f0446eb96c67c215d8d707bce2655a98ddf1c0b71f848484846040516126f89493929190614d0f565b60405180910390a150505050565b60606000806000806127166137b6565b600087815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff908116848801526001850154918216848701529190048116606083015260029092015463ffffffff808216608084015264010000000082041660a083015268010000000000000000810490921660c08201527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e08201528a8452600b90925280832090519192917f6e04ff0d000000000000000000000000000000000000000000000000000000009161282691602401614ee9565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808360c0015173ffffffffffffffffffffffffffffffffffffffff16600d600001600b9054906101000a900463ffffffff1663ffffffff16846040516128cd9190614cf3565b60006040518083038160008787f1925050503d806000811461290b576040519150601f19603f3d011682016040523d82523d6000602084013e612910565b606091505b50915091508161294e57806040517f96c36235000000000000000000000000000000000000000000000000000000008152600401610b469190614e9f565b808060200190518101906129629190614a15565b995091508161299d576040517f865676e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006129ac8b8d8c60006137ee565b90506129c185826000015183606001516138d8565b60608101516080820151600d5460a08401518d9392916129fc91720100000000000000000000000000000000000090910461ffff169061517b565b60c090940151929f919e509c50919a5098509650505050505050565b600081815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811696840196909652600184015490811694830194909452909204831660608301526002015463ffffffff80821660808401526401000000008204811660a08401819052680100000000000000008304851660c08501527c010000000000000000000000000000000000000000000000000000000090920460ff16151560e08401529354919314801592919091163314908290612b1e5750808015612b1c5750438360a0015163ffffffff16115b155b15612b55576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015612b935750826060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15612bca576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4381612bde57612bdb6032826150f8565b90505b6000858152600760205260409020600201805463ffffffff808416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117909155612c3a9060059087906133cb16565b50600d5460408501516bffffffffffffffffffffffff7401000000000000000000000000000000000000000090920482169160009116821115612cb4576040860151612c8690836151cf565b905085600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115612cb4575084515b8551612cc19082906151cf565b600088815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154612d1591839116615110565b601180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590612dd3575060145473ffffffffffffffffffffffffffffffffffffffff163314155b15612e0a576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e156001436151b8565b600e5460408051924060208401523060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690830152640100000000900460e01b7fffffffff000000000000000000000000000000000000000000000000000000001660548201526058016040516020818303038152906040528051906020012060001c9050612ee281878787600088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525092506133e0915050565b600e8054640100000000900463ffffffff16906004612f00836152b5565b91906101000a81548163ffffffff021916908363ffffffff16021790555050807fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128686604051612f7892919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a295945050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260086020526040902054163314612fe9576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331415613039576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260096020526040902054811690821614610d355773ffffffffffffffffffffffffffffffffffffffff82811660008181526009602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b6130f06130fc565b6130f981613a29565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b46565b806060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131e6576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015163ffffffff908116146130f9576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60035460ff16613296576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b46565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60035460ff1615613378576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b46565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132e13390565b60006133d78383613b1f565b90505b92915050565b60035460ff161561344d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b46565b73ffffffffffffffffffffffffffffffffffffffff86163b61349b576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8563ffffffff1610806134bc5750600e5463ffffffff908116908616115b156134f3576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101000160405280846bffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018663ffffffff16815260200163ffffffff801681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018215158152506007600089815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160020160086101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060e082015181600201601c6101000a81548160ff021916908315150217905550905050826bffffffffffffffffffffffff1660125461377e91906150f8565b6012556000878152600b6020908152604090912083516137a09285019061439b565b506137ac600588613c12565b5050505050505050565b3215610780576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6138446040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206002015463ffffffff169080613866613c1e565b91509150600061387884848489613e19565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff909b168b5260208b0199909952978901969096526bffffffffffffffffffffffff9096166060880152608087019190915260a086015250505060c082015290565b8260e0015115613914576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff16613976576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff168111156139bf576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff16141561076b576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331415613aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b46565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008181526001830160205260408120548015613c08576000613b436001836151b8565b8554909150600090613b57906001906151b8565b9050818114613bbc576000866000018281548110613b7757613b77615366565b9060005260206000200154905080876000018481548110613b9a57613b9a615366565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613bcd57613bcd615337565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506133da565b60009150506133da565b60006133d7838361428a565b6000806000600d600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015613cb557600080fd5b505afa158015613cc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ced9190614b99565b509450909250849150508015613d115750613d0882426151b8565b8463ffffffff16105b80613d1d575060008113155b15613d2c57600f549550613d30565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015613d9657600080fd5b505afa158015613daa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dce9190614b99565b509450909250849150508015613df25750613de982426151b8565b8463ffffffff16105b80613dfe575060008113155b15613e0d576010549450613e11565b8094505b505050509091565b6040805161012081018252600d5463ffffffff80821683526401000000008083048216602085015268010000000000000000830462ffffff908116958501959095526b0100000000000000000000008304821660608501526f01000000000000000000000000000000830490941660808401527201000000000000000000000000000000000000820461ffff1660a08401819052740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1660c0840152600e5480821660e0850152939093049092166101008201526000918290613f00908761517b565b9050838015613f0e5750803a105b15613f1657503a5b6000613f427f0000000000000000000000000000000000000000000000000000000000000000896150f8565b613f4c908361517b565b8351909150600090613f689063ffffffff16633b9aca006150f8565b9050600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613fa057613fa0615308565b14156140e8576040805160008152602081019091528715613fff5760003660405180608001604052806048815260200161540a60489139604051602001613fe993929190614ccc565b604051602081830303815290604052905061401e565b6040518061014001604052806101108152602001615452610110913990505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906349948e0e90614090908490600401614e9f565b60206040518083038186803b1580156140a857600080fd5b505afa1580156140bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e09190614b17565b9150506141c3565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111561411c5761411c615308565b14156141c3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561418857600080fd5b505afa15801561419c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c09190614b17565b90505b866141df57808560a0015161ffff166141dc919061517b565b90505b6000856020015163ffffffff1664e8d4a510006141fc919061517b565b898461420885886150f8565b61421690633b9aca0061517b565b614220919061517b565b61422a9190615140565b61423491906150f8565b90506b033b2e3c9fd0803ce800000081111561427c576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b60008181526001830160205260408120546142d1575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556133da565b5060006133da565b5080546142e590615228565b6000825580601f106142f5575050565b601f0160209004906000526020600020908101906130f9919061440f565b82805482825590600052602060002090810192821561438b579160200282015b8281111561438b5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190614333565b5061439792915061440f565b5090565b8280546143a790615228565b90600052602060002090601f0160209004810192826143c9576000855561438b565b82601f106143e257805160ff191683800117855561438b565b8280016001018555821561438b579182015b8281111561438b5782518255916020019190600101906143f4565b5b808211156143975760008155600101614410565b803573ffffffffffffffffffffffffffffffffffffffff8116811461444857600080fd5b919050565b60008083601f84011261445f57600080fd5b50813567ffffffffffffffff81111561447757600080fd5b6020830191508360208260051b850101111561449257600080fd5b9250929050565b600082601f8301126144aa57600080fd5b813560206144bf6144ba8361508e565b61503f565b80838252828201915082860187848660051b89010111156144df57600080fd5b60005b8581101561455f57813567ffffffffffffffff81111561450157600080fd5b8801603f81018a1361451257600080fd5b8581013560406145246144ba836150b2565b8281528c8284860101111561453857600080fd5b828285018a83013760009281018901929092525085525092840192908401906001016144e2565b5090979650505050505050565b600082601f83011261457d57600080fd5b8135602061458d6144ba8361508e565b80838252828201915082860187848660081b89010111156145ad57600080fd5b6000805b868110156146675761010080848c0312156145ca578283fd5b6145d2615015565b6145db85614732565b81526145e8888601614424565b8882015260406145f9818701614732565b90820152606061460a868201614424565b90820152608061461b868201614704565b9082015260a061462c868201614704565b9082015260c061463d868201614424565b9082015260e085810135614650816153fb565b9082015286529486019492909201916001016145b1565b509198975050505050505050565b60008083601f84011261468757600080fd5b50813567ffffffffffffffff81111561469f57600080fd5b60208301915083602082850101111561449257600080fd5b600082601f8301126146c857600080fd5b81516146d66144ba826150b2565b8181528460208386010111156146eb57600080fd5b6146fc8260208301602087016151fc565b949350505050565b803563ffffffff8116811461444857600080fd5b805169ffffffffffffffffffff8116811461444857600080fd5b80356bffffffffffffffffffffffff8116811461444857600080fd5b60006020828403121561476057600080fd5b6133d782614424565b6000806040838503121561477c57600080fd5b61478583614424565b915061479360208401614424565b90509250929050565b600080604083850312156147af57600080fd5b6147b883614424565b91506020830135600481106147cc57600080fd5b809150509250929050565b6000806000806000608086880312156147ef57600080fd5b6147f886614424565b945061480660208701614704565b935061481460408701614424565b9250606086013567ffffffffffffffff81111561483057600080fd5b61483c88828901614675565b969995985093965092949392505050565b6000806000806040858703121561486357600080fd5b843567ffffffffffffffff8082111561487b57600080fd5b6148878883890161444d565b909650945060208701359150808211156148a057600080fd5b506148ad8782880161444d565b95989497509550505050565b6000806000604084860312156148ce57600080fd5b833567ffffffffffffffff8111156148e557600080fd5b6148f18682870161444d565b9094509250614904905060208501614424565b90509250925092565b60008060006060848603121561492257600080fd5b833567ffffffffffffffff8082111561493a57600080fd5b818601915086601f83011261494e57600080fd5b8135602061495e6144ba8361508e565b8083825282820191508286018b848660051b890101111561497e57600080fd5b600096505b848710156149a1578035835260019690960195918301918301614983565b50975050870135925050808211156149b857600080fd5b6149c48783880161456c565b935060408601359150808211156149da57600080fd5b506149e786828701614499565b9150509250925092565b600060208284031215614a0357600080fd5b8151614a0e816153fb565b9392505050565b60008060408385031215614a2857600080fd5b8251614a33816153fb565b602084015190925067ffffffffffffffff811115614a5057600080fd5b614a5c858286016146b7565b9150509250929050565b60008060208385031215614a7957600080fd5b823567ffffffffffffffff811115614a9057600080fd5b614a9c85828601614675565b90969095509350505050565b600060208284031215614aba57600080fd5b815167ffffffffffffffff811115614ad157600080fd5b6146fc848285016146b7565b600060208284031215614aef57600080fd5b815160038110614a0e57600080fd5b600060208284031215614b1057600080fd5b5035919050565b600060208284031215614b2957600080fd5b5051919050565b60008060408385031215614b4357600080fd5b8235915061479360208401614424565b60008060408385031215614b6657600080fd5b8235915061479360208401614704565b60008060408385031215614b8957600080fd5b8235915061479360208401614732565b600080600080600060a08688031215614bb157600080fd5b614bba86614718565b9450602086015193506040860151925060608601519150614bdd60808701614718565b90509295509295909350565b8183526000602080850194508260005b85811015614c325773ffffffffffffffffffffffffffffffffffffffff614c1f83614424565b1687529582019590820190600101614bf9565b509495945050505050565b6000815180845260208085019450848260051b860182860160005b8581101561455f578383038952614c70838351614c82565b98850198925090840190600101614c58565b60008151808452614c9a8160208601602086016151fc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b828482376000838201600081528351614ce98183602088016151fc565b0195945050505050565b60008251614d058184602087016151fc565b9190910192915050565b604081526000614d23604083018688614be9565b8281036020840152614d36818587614be9565b979650505050505050565b60006060808352858184015260807f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff871115614d7c57600080fd5b8660051b808983870137808501905081810160008152602083878403018188015281895180845260a093508385019150828b01945060005b81811015614e7b5785516bffffffffffffffffffffffff80825116855273ffffffffffffffffffffffffffffffffffffffff868301511686860152604081818401511681870152505088810151614e228a86018273ffffffffffffffffffffffffffffffffffffffff169052565b508781015163ffffffff908116858a015286820151168685015260c08082015173ffffffffffffffffffffffffffffffffffffffff169085015260e0908101511515908401529483019461010090920191600101614db4565b50508781036040890152614e8f818a614c3d565b9c9b505050505050505050505050565b6020815260006133d76020830184614c82565b60a081526000614ec560a0830188614c82565b90508560208301528460408301528360608301528260808301529695505050505050565b600060208083526000845481600182811c915080831680614f0b57607f831692505b858310811415614f42577f4e487b710000000000000000000000000000000000000000000000000000000085526022600452602485fd5b878601838152602001818015614f5f5760018114614f8e57614fb9565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861682528782019650614fb9565b60008b81526020902060005b86811015614fb357815484820152908501908901614f9a565b83019750505b50949998505050505050505050565b60208101614fd5836153c4565b91905290565b614fe4846153c4565b838152614ff0836153c4565b82602082015260606040820152600061500c6060830184614c82565b95945050505050565b604051610100810167ffffffffffffffff8111828210171561503957615039615395565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561508657615086615395565b604052919050565b600067ffffffffffffffff8211156150a8576150a8615395565b5060051b60200190565b600067ffffffffffffffff8211156150cc576150cc615395565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b6000821982111561510b5761510b6152d9565b500190565b60006bffffffffffffffffffffffff808316818516808303821115615137576151376152d9565b01949350505050565b600082615176577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156151b3576151b36152d9565b500290565b6000828210156151ca576151ca6152d9565b500390565b60006bffffffffffffffffffffffff838116908316818110156151f4576151f46152d9565b039392505050565b60005b838110156152175781810151838201526020016151ff565b83811115611ce15750506000910152565b600181811c9082168061523c57607f821691505b60208210811415615276577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156152ae576152ae6152d9565b5060010190565b600063ffffffff808316818114156152cf576152cf6152d9565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600381106130f9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80151581146130f957600080fdfe3078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666663078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + Bin: "0x6101606040527f420000000000000000000000000000000000000f00000000000000000000000060e0526c6c000000000000000000000000610100523480156200004857600080fd5b50604051620058fa380380620058fa8339810160408190526200006b916200028f565b84848484843380600081620000c75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000fa57620000fa81620001c6565b5050600160029081556003805460ff19169055869150811115620001225762000122620002fc565b6101208160028111156200013a576200013a620002fc565b60f81b9052506101408490526001600160a01b03831615806200016457506001600160a01b038216155b806200017757506001600160a01b038116155b156200019657604051637138356f60e01b815260040160405180910390fd5b6001600160601b0319606093841b811660805291831b821660a05290911b1660c052506200031295505050505050565b6001600160a01b038116331415620002215760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000be565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028a57600080fd5b919050565b600080600080600060a08688031215620002a857600080fd5b855160038110620002b857600080fd5b60208701519095509350620002d06040870162000272565b9250620002e06060870162000272565b9150620002f06080870162000272565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160f81c61014051615519620003e16000396000818161028c0152613ec801526000818161036301528181613f1b01526140970152600081816102fa01526140cf01526000818161032901526140060152600081816102650152613bfc0152600081816104010152613cdd01526000818161020c01528181610a4601528181610ca30152818161150e0152818161197301528181611c6301528181612273015261230601526155196000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80638da5cb5b11610104578063b148ab6b116100a2578063c804802211610071578063c804802214610488578063da5c67411461049b578063eb5dcd6c146104ae578063f2fde38b146104c157600080fd5b8063b148ab6b14610436578063b79550be14610449578063b7fdb43614610451578063c41b813a1461046457600080fd5b8063a710b221116100de578063a710b221146103d6578063a72aa27e146103e9578063ad178361146103fc578063b121e1471461042357600080fd5b80638da5cb5b146103925780638e86139b146103b0578063948108f7146103c357600080fd5b8063744bfe611161017c5780638456cb591161014b5780638456cb591461031c578063850cce341461032457806385c1b0ba1461034b5780638811cbe81461035e57600080fd5b8063744bfe61146102d257806379ba5097146102e55780637d9b97e0146102ed5780637f37618e146102f557600080fd5b80633f4ba83a116101b85780633f4ba83a146102585780634584a419146102605780635077b210146102875780635c975abb146102bc57600080fd5b8063187256e8146101df5780631a2af011146101f45780631b6b6d2314610207575b600080fd5b6101f26101ed366004614747565b6104d4565b005b6101f2610202366004614adb565b610545565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6101f2610770565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6102ae7f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161024f565b60035460ff16604051901515815260200161024f565b6101f26102e0366004614adb565b610782565b6101f2610ac9565b6101f2610bcb565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f2610d39565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f2610359366004614864565b610d49565b6103857f000000000000000000000000000000000000000000000000000000000000000081565b60405161024f9190614f73565b60005473ffffffffffffffffffffffffffffffffffffffff1661022e565b6101f26103be366004614a11565b611598565b6101f26103d1366004614b21565b6117b6565b6101f26103e4366004614714565b611a4f565b6101f26103f7366004614afe565b611ce7565b61022e7f000000000000000000000000000000000000000000000000000000000000000081565b6101f26104313660046146f9565b611f20565b6101f2610444366004614aa9565b612018565b6101f261223a565b6101f261045f3660046147f8565b6123a5565b610477610472366004614adb565b612706565b60405161024f959493929190614e5d565b6101f2610496366004614aa9565b612a18565b6102ae6104a9366004614782565b612d92565b6101f26104bc366004614714565b612f89565b6101f26104cf3660046146f9565b6130e8565b6104dc6130fc565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561053c5761053c6152b3565b02179055505050565b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e08201526106248161317d565b73ffffffffffffffffffffffffffffffffffffffff8216331415610674576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166106c1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff83811691161461076b576000838152600a602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590519091339186917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b505050565b6107786130fc565b61078061322a565b565b73ffffffffffffffffffffffffffffffffffffffff81166107cf576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff9081169584019590955260018401549081169583019590955290930482166060840181905260029091015463ffffffff808216608086015264010000000082041660a085015268010000000000000000810490921660c08401527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e083015233146108e2576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b438160a0015163ffffffff161115610926576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600760205260409020546012546bffffffffffffffffffffffff90911690610954908290615163565b60125560008481526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016905581516bffffffffffffffffffffffff8416815273ffffffffffffffffffffffffffffffffffffffff86169181019190915285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a26040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b158015610a8a57600080fd5b505af1158015610a9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac2919061499c565b5050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610bd36130fc565b6011546012546bffffffffffffffffffffffff90911690610bf5908290615163565b601255601180547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b602060405180830381600087803b158015610cfd57600080fd5b505af1158015610d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d35919061499c565b5050565b610d416130fc565b6107806132a7565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff166003811115610d8557610d856152b3565b14158015610dcd5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff166003811115610dca57610dca6152b3565b14155b15610e04576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60135473ffffffffffffffffffffffffffffffffffffffff16610e53576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610e8a576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526000808567ffffffffffffffff811115610ee657610ee6615340565b604051908082528060200260200182016040528015610f1957816020015b6060815260200190600190039081610f045790505b50905060008667ffffffffffffffff811115610f3757610f37615340565b604051908082528060200260200182016040528015610fc457816020015b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610f555790505b50905060005b878110156112ce57888882818110610fe457610fe4615311565b6020908102929092013560008181526007845260409081902081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811698840198909852600184015490811694830194909452909204851660608301526002015463ffffffff808216608084015264010000000082041660a083015268010000000000000000810490941660c08201527c010000000000000000000000000000000000000000000000000000000090930460ff16151560e084015297509095506110d290508561317d565b848282815181106110e5576110e5615311565b6020026020010181905250600b6000878152602001908152602001600020805461110e906151d3565b80601f016020809104026020016040519081016040528092919081815260200182805461113a906151d3565b80156111875780601f1061115c57610100808354040283529160200191611187565b820191906000526020600020905b81548152906001019060200180831161116a57829003601f168201915b505050505083828151811061119e5761119e615311565b602090810291909101015284516111c3906bffffffffffffffffffffffff16856150a3565b60008781526007602090815260408083208381556001810184905560020180547fffffff0000000000000000000000000000000000000000000000000000000000169055600b909152812091955061121b9190614284565b6000868152600a6020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561125a600587613302565b508451604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8916602083015287917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a2806112c681615227565b915050610fca565b50826012546112dd9190615163565b6012556040516000906112fa908a908a9085908790602001614cec565b60405160208183030381529060405290508673ffffffffffffffffffffffffffffffffffffffff16638e86139b601360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60018b73ffffffffffffffffffffffffffffffffffffffff166348013d7b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113ad57600080fd5b505afa1580156113c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e59190614a88565b866040518463ffffffff1660e01b815260040161140493929190614f86565b60006040518083038186803b15801561141c57600080fd5b505afa158015611430573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114769190810190614a53565b6040518263ffffffff1660e01b81526004016114929190614e4a565b600060405180830381600087803b1580156114ac57600080fd5b505af11580156114c0573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152602482018890527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb9150604401602060405180830381600087803b15801561155457600080fd5b505af1158015611568573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158c919061499c565b50505050505050505050565b6002336000908152600c602052604090205460ff1660038111156115be576115be6152b3565b141580156115f057506003336000908152600c602052604090205460ff1660038111156115ed576115ed6152b3565b14155b15611627576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611637848601866148b8565b92509250925060005b83518110156117ae5761171b84828151811061165e5761165e615311565b602002602001015184838151811061167857611678615311565b602002602001015160c0015185848151811061169657611696615311565b6020026020010151608001518685815181106116b4576116b4615311565b6020026020010151606001518786815181106116d2576116d2615311565b6020026020010151600001518787815181106116f0576116f0615311565b602002602001015189888151811061170a5761170a615311565b602002602001015160e00151613317565b83818151811061172d5761172d615311565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7184838151811061176857611768615311565b60209081029190910181015151604080516bffffffffffffffffffffffff909216825233928201929092520160405180910390a2806117a681615227565b915050611640565b505050505050565b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e0840152146118c7576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516118d49083906150bb565b600084815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601254611928918416906150a3565b6012556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b1580156119cc57600080fd5b505af11580156119e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a04919061499c565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8116611a9c576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16928101929092526001015460ff16151591810191909152903314611b4d576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff80841660009081526008602090815260409091208054909216909155810151601254611b9c916bffffffffffffffffffffffff1690615163565b60125560208082015160405133815273ffffffffffffffffffffffffffffffffffffffff808616936bffffffffffffffffffffffff90931692908716917f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698910160405180910390a460208101516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff90921660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015611ca957600080fd5b505af1158015611cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce1919061499c565b50505050565b6108fc8163ffffffff161080611d085750600e5463ffffffff908116908216115b15611d3f576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e084015214611e50576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015173ffffffffffffffffffffffffffffffffffffffff163314611ea3576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602090815260409182902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8616908117909155915191825284917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a2505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260096020526040902054163314611f80576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526008602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556009909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff80821660808501526401000000008204811660a0850181905268010000000000000000830490931660c08501527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e084015214612129576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612186576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060810151600083815260076020908152604080832060010180546bffffffffffffffffffffffff16336c01000000000000000000000000810291909117909155600a90925280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905551909173ffffffffffffffffffffffffffffffffffffffff84169186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b6122426130fc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156122ca57600080fd5b505afa1580156122de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123029190614ac2565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb336012548461234f9190615163565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401610ce3565b6123ad6130fc565b82811415806123bc5750600283105b156123f3576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60045481101561247f5760006004828154811061241557612415615311565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168252600890526040902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055508061247781615227565b9150506123f6565b5060005b838110156126b557600085858381811061249f5761249f615311565b90506020020160208101906124b491906146f9565b73ffffffffffffffffffffffffffffffffffffffff8082166000908152600860205260408120805493945092909116908686868181106124f6576124f6615311565b905060200201602081019061250b91906146f9565b905073ffffffffffffffffffffffffffffffffffffffff8116158061259e575073ffffffffffffffffffffffffffffffffffffffff82161580159061257c57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561259e575073ffffffffffffffffffffffffffffffffffffffff81811614155b156125d5576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183015460ff1615612614576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905573ffffffffffffffffffffffffffffffffffffffff8181161461269e5782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783555b5050505080806126ad90615227565b915050612483565b506126c2600485856142be565b507f056264c94f28bb06c99d13f0446eb96c67c215d8d707bce2655a98ddf1c0b71f848484846040516126f89493929190614cba565b60405180910390a150505050565b6060600080600080612716613688565b600087815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff908116848801526001850154918216848701529190048116606083015260029092015463ffffffff808216608084015264010000000082041660a083015268010000000000000000810490921660c08201527c010000000000000000000000000000000000000000000000000000000090910460ff16151560e08201528a8452600b90925280832090519192917f6e04ff0d000000000000000000000000000000000000000000000000000000009161282691602401614e94565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808360c0015173ffffffffffffffffffffffffffffffffffffffff16600d600001600b9054906101000a900463ffffffff1663ffffffff16846040516128cd9190614c9e565b60006040518083038160008787f1925050503d806000811461290b576040519150601f19603f3d011682016040523d82523d6000602084013e612910565b606091505b50915091508161294e57806040517f96c36235000000000000000000000000000000000000000000000000000000008152600401610b469190614e4a565b8080602001905181019061296291906149c0565b995091508161299d576040517f865676e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006129ac8b8d8c60006136c0565b90506129c185826000015183606001516137aa565b60608101516080820151600d5460a08401518d9392916129fc91720100000000000000000000000000000000000090910461ffff1690615126565b60c090940151929f919e509c50919a5098509650505050505050565b600081815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff90811696840196909652600184015490811694830194909452909204831660608301526002015463ffffffff80821660808401526401000000008204811660a08401819052680100000000000000008304851660c08501527c010000000000000000000000000000000000000000000000000000000090920460ff16151560e08401529354919314801592919091163314908290612b1e5750808015612b1c5750438360a0015163ffffffff16115b155b15612b55576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015612b935750826060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614155b15612bca576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4381612bde57612bdb6032826150a3565b90505b6000858152600760205260409020600201805463ffffffff808416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117909155612c3a90600590879061330216565b50600d5460408501516bffffffffffffffffffffffff7401000000000000000000000000000000000000000090920482169160009116821115612cb4576040860151612c86908361517a565b905085600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115612cb4575084515b8551612cc190829061517a565b600088815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154612d15918391166150bb565b601180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590612dd3575060145473ffffffffffffffffffffffffffffffffffffffff163314155b15612e0a576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e15600143615163565b600e5460408051924060208401523060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690830152640100000000900460e01b7fffffffff000000000000000000000000000000000000000000000000000000001660548201526058016040516020818303038152906040528051906020012060001c9050612ee281878787600088888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250613317915050565b600e8054640100000000900463ffffffff16906004612f0083615260565b91906101000a81548163ffffffff021916908363ffffffff16021790555050807fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128686604051612f7892919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a295945050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260086020526040902054163314612fe9576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331415613039576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260096020526040902054811690821614610d355773ffffffffffffffffffffffffffffffffffffffff82811660008181526009602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b6130f06130fc565b6130f9816138fb565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b46565b806060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131e6576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015163ffffffff908116146130f9576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6132326139f1565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6132af613a5d565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861327d3390565b600061330e8383613aca565b90505b92915050565b61331f613a5d565b73ffffffffffffffffffffffffffffffffffffffff86163b61336d576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8563ffffffff16108061338e5750600e5463ffffffff908116908616115b156133c5576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101000160405280846bffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018663ffffffff16815260200163ffffffff801681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018215158152506007600089815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060808201518160020160006101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160020160046101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160020160086101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060e082015181600201601c6101000a81548160ff021916908315150217905550905050826bffffffffffffffffffffffff1660125461365091906150a3565b6012556000878152600b60209081526040909120835161367292850190614346565b5061367e600588613bbd565b5050505050505050565b3215610780576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6137166040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206002015463ffffffff169080613738613bc9565b91509150600061374a84848489613dc4565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff909b168b5260208b0199909952978901969096526bffffffffffffffffffffffff9096166060880152608087019190915260a086015250505060c082015290565b8260e00151156137e6576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff16613848576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff16811115613891576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff16141561076b576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811633141561397b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b46565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60035460ff16610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b46565b60035460ff1615610780576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b46565b60008181526001830160205260408120548015613bb3576000613aee600183615163565b8554909150600090613b0290600190615163565b9050818114613b67576000866000018281548110613b2257613b22615311565b9060005260206000200154905080876000018481548110613b4557613b45615311565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613b7857613b786152e2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050613311565b6000915050613311565b600061330e8383614235565b6000806000600d600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015613c6057600080fd5b505afa158015613c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c989190614b44565b509450909250849150508015613cbc5750613cb38242615163565b8463ffffffff16105b80613cc8575060008113155b15613cd757600f549550613cdb565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015613d4157600080fd5b505afa158015613d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d799190614b44565b509450909250849150508015613d9d5750613d948242615163565b8463ffffffff16105b80613da9575060008113155b15613db8576010549450613dbc565b8094505b505050509091565b6040805161012081018252600d5463ffffffff80821683526401000000008083048216602085015268010000000000000000830462ffffff908116958501959095526b0100000000000000000000008304821660608501526f01000000000000000000000000000000830490941660808401527201000000000000000000000000000000000000820461ffff1660a08401819052740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1660c0840152600e5480821660e0850152939093049092166101008201526000918290613eab9087615126565b9050838015613eb95750803a105b15613ec157503a5b6000613eed7f0000000000000000000000000000000000000000000000000000000000000000896150a3565b613ef79083615126565b8351909150600090613f139063ffffffff16633b9aca006150a3565b9050600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613f4b57613f4b6152b3565b1415614093576040805160008152602081019091528715613faa576000366040518060800160405280604881526020016153b560489139604051602001613f9493929190614c77565b6040516020818303038152906040529050613fc9565b60405180610140016040528061011081526020016153fd610110913990505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906349948e0e9061403b908490600401614e4a565b60206040518083038186803b15801561405357600080fd5b505afa158015614067573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061408b9190614ac2565b91505061416e565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156140c7576140c76152b3565b141561416e577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561413357600080fd5b505afa158015614147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061416b9190614ac2565b90505b8661418a57808560a0015161ffff166141879190615126565b90505b6000856020015163ffffffff1664e8d4a510006141a79190615126565b89846141b385886150a3565b6141c190633b9aca00615126565b6141cb9190615126565b6141d591906150eb565b6141df91906150a3565b90506b033b2e3c9fd0803ce8000000811115614227576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b600081815260018301602052604081205461427c57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155613311565b506000613311565b508054614290906151d3565b6000825580601f106142a0575050565b601f0160209004906000526020600020908101906130f991906143ba565b828054828255906000526020600020908101928215614336579160200282015b828111156143365781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8435161782556020909201916001909101906142de565b506143429291506143ba565b5090565b828054614352906151d3565b90600052602060002090601f0160209004810192826143745760008555614336565b82601f1061438d57805160ff1916838001178555614336565b82800160010185558215614336579182015b8281111561433657825182559160200191906001019061439f565b5b8082111561434257600081556001016143bb565b803573ffffffffffffffffffffffffffffffffffffffff811681146143f357600080fd5b919050565b60008083601f84011261440a57600080fd5b50813567ffffffffffffffff81111561442257600080fd5b6020830191508360208260051b850101111561443d57600080fd5b9250929050565b600082601f83011261445557600080fd5b8135602061446a61446583615039565b614fea565b80838252828201915082860187848660051b890101111561448a57600080fd5b60005b8581101561450a57813567ffffffffffffffff8111156144ac57600080fd5b8801603f81018a136144bd57600080fd5b8581013560406144cf6144658361505d565b8281528c828486010111156144e357600080fd5b828285018a830137600092810189019290925250855250928401929084019060010161448d565b5090979650505050505050565b600082601f83011261452857600080fd5b8135602061453861446583615039565b80838252828201915082860187848660081b890101111561455857600080fd5b6000805b868110156146125761010080848c031215614575578283fd5b61457d614fc0565b614586856146dd565b81526145938886016143cf565b8882015260406145a48187016146dd565b9082015260606145b58682016143cf565b9082015260806145c68682016146af565b9082015260a06145d78682016146af565b9082015260c06145e88682016143cf565b9082015260e0858101356145fb816153a6565b90820152865294860194929092019160010161455c565b509198975050505050505050565b60008083601f84011261463257600080fd5b50813567ffffffffffffffff81111561464a57600080fd5b60208301915083602082850101111561443d57600080fd5b600082601f83011261467357600080fd5b81516146816144658261505d565b81815284602083860101111561469657600080fd5b6146a78260208301602087016151a7565b949350505050565b803563ffffffff811681146143f357600080fd5b805169ffffffffffffffffffff811681146143f357600080fd5b80356bffffffffffffffffffffffff811681146143f357600080fd5b60006020828403121561470b57600080fd5b61330e826143cf565b6000806040838503121561472757600080fd5b614730836143cf565b915061473e602084016143cf565b90509250929050565b6000806040838503121561475a57600080fd5b614763836143cf565b915060208301356004811061477757600080fd5b809150509250929050565b60008060008060006080868803121561479a57600080fd5b6147a3866143cf565b94506147b1602087016146af565b93506147bf604087016143cf565b9250606086013567ffffffffffffffff8111156147db57600080fd5b6147e788828901614620565b969995985093965092949392505050565b6000806000806040858703121561480e57600080fd5b843567ffffffffffffffff8082111561482657600080fd5b614832888389016143f8565b9096509450602087013591508082111561484b57600080fd5b50614858878288016143f8565b95989497509550505050565b60008060006040848603121561487957600080fd5b833567ffffffffffffffff81111561489057600080fd5b61489c868287016143f8565b90945092506148af9050602085016143cf565b90509250925092565b6000806000606084860312156148cd57600080fd5b833567ffffffffffffffff808211156148e557600080fd5b818601915086601f8301126148f957600080fd5b8135602061490961446583615039565b8083825282820191508286018b848660051b890101111561492957600080fd5b600096505b8487101561494c57803583526001969096019591830191830161492e565b509750508701359250508082111561496357600080fd5b61496f87838801614517565b9350604086013591508082111561498557600080fd5b5061499286828701614444565b9150509250925092565b6000602082840312156149ae57600080fd5b81516149b9816153a6565b9392505050565b600080604083850312156149d357600080fd5b82516149de816153a6565b602084015190925067ffffffffffffffff8111156149fb57600080fd5b614a0785828601614662565b9150509250929050565b60008060208385031215614a2457600080fd5b823567ffffffffffffffff811115614a3b57600080fd5b614a4785828601614620565b90969095509350505050565b600060208284031215614a6557600080fd5b815167ffffffffffffffff811115614a7c57600080fd5b6146a784828501614662565b600060208284031215614a9a57600080fd5b8151600381106149b957600080fd5b600060208284031215614abb57600080fd5b5035919050565b600060208284031215614ad457600080fd5b5051919050565b60008060408385031215614aee57600080fd5b8235915061473e602084016143cf565b60008060408385031215614b1157600080fd5b8235915061473e602084016146af565b60008060408385031215614b3457600080fd5b8235915061473e602084016146dd565b600080600080600060a08688031215614b5c57600080fd5b614b65866146c3565b9450602086015193506040860151925060608601519150614b88608087016146c3565b90509295509295909350565b8183526000602080850194508260005b85811015614bdd5773ffffffffffffffffffffffffffffffffffffffff614bca836143cf565b1687529582019590820190600101614ba4565b509495945050505050565b6000815180845260208085019450848260051b860182860160005b8581101561450a578383038952614c1b838351614c2d565b98850198925090840190600101614c03565b60008151808452614c458160208601602086016151a7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b828482376000838201600081528351614c948183602088016151a7565b0195945050505050565b60008251614cb08184602087016151a7565b9190910192915050565b604081526000614cce604083018688614b94565b8281036020840152614ce1818587614b94565b979650505050505050565b60006060808352858184015260807f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff871115614d2757600080fd5b8660051b808983870137808501905081810160008152602083878403018188015281895180845260a093508385019150828b01945060005b81811015614e265785516bffffffffffffffffffffffff80825116855273ffffffffffffffffffffffffffffffffffffffff868301511686860152604081818401511681870152505088810151614dcd8a86018273ffffffffffffffffffffffffffffffffffffffff169052565b508781015163ffffffff908116858a015286820151168685015260c08082015173ffffffffffffffffffffffffffffffffffffffff169085015260e0908101511515908401529483019461010090920191600101614d5f565b50508781036040890152614e3a818a614be8565b9c9b505050505050505050505050565b60208152600061330e6020830184614c2d565b60a081526000614e7060a0830188614c2d565b90508560208301528460408301528360608301528260808301529695505050505050565b600060208083526000845481600182811c915080831680614eb657607f831692505b858310811415614eed577f4e487b710000000000000000000000000000000000000000000000000000000085526022600452602485fd5b878601838152602001818015614f0a5760018114614f3957614f64565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861682528782019650614f64565b60008b81526020902060005b86811015614f5e57815484820152908501908901614f45565b83019750505b50949998505050505050505050565b60208101614f808361536f565b91905290565b614f8f8461536f565b838152614f9b8361536f565b826020820152606060408201526000614fb76060830184614c2d565b95945050505050565b604051610100810167ffffffffffffffff81118282101715614fe457614fe4615340565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561503157615031615340565b604052919050565b600067ffffffffffffffff82111561505357615053615340565b5060051b60200190565b600067ffffffffffffffff82111561507757615077615340565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082198211156150b6576150b6615284565b500190565b60006bffffffffffffffffffffffff8083168185168083038211156150e2576150e2615284565b01949350505050565b600082615121577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561515e5761515e615284565b500290565b60008282101561517557615175615284565b500390565b60006bffffffffffffffffffffffff8381169083168181101561519f5761519f615284565b039392505050565b60005b838110156151c25781810151838201526020016151aa565b83811115611ce15750506000910152565b600181811c908216806151e757607f821691505b60208210811415615221577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561525957615259615284565b5060010190565b600063ffffffff8083168181141561527a5761527a615284565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600381106130f9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80151581146130f957600080fdfe3078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666663078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var KeeperRegistryLogicABI = KeeperRegistryLogicMetaData.ABI diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go b/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go index 6eb008160a5..cbfd589abf4 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_2/keeper_registry_wrapper1_2.go @@ -54,7 +54,7 @@ type State struct { var KeeperRegistryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fastGasFeed\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeepersMustTakeTurns\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveKeepers\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotActive\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"KeepersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"executeGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"FAST_GAS_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxLinkPayment\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"adjustedGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkEth\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getKeeperInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"enumKeeperRegistry1_2.MigrationPermission\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"}],\"internalType\":\"structState\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"executeGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"lastKeeper\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setKeepers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"enumKeeperRegistry1_2.MigrationPermission\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"enumUpkeepFormat\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b50604051620067a8380380620067a8833981016040819052620000349162000577565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000107565b50506001600255506003805460ff191690556001600160601b0319606085811b821660805284811b821660a05283901b1660c052620000fd81620001b3565b50505050620007fa565b6001600160a01b038116331415620001625760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001bd620004a8565b600d5460e082015163ffffffff91821691161015620001ef57604051630e6af04160e21b815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516001600160601b031681526020018260e0015163ffffffff168152602001600c60010160049054906101000a900463ffffffff1663ffffffff16815250600c60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600e81905550806101200151600f81905550806101400151601260006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806101600151601360006101000a8154816001600160a01b0302191690836001600160a01b031602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de325816040516200049d9190620006c3565b60405180910390a150565b6000546001600160a01b03163314620005045760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b80516001600160a01b03811681146200051e57600080fd5b919050565b805161ffff811681146200051e57600080fd5b805162ffffff811681146200051e57600080fd5b805163ffffffff811681146200051e57600080fd5b80516001600160601b03811681146200051e57600080fd5b6000806000808486036101e08112156200059057600080fd5b6200059b8662000506565b9450620005ab6020870162000506565b9350620005bb6040870162000506565b925061018080605f1983011215620005d257600080fd5b620005dc620007c2565b9150620005ec606088016200054a565b8252620005fc608088016200054a565b60208301526200060f60a0880162000536565b60408301526200062260c088016200054a565b60608301526200063560e0880162000536565b60808301526101006200064a81890162000523565b60a08401526101206200065f818a016200055f565b60c085015261014062000674818b016200054a565b60e0860152610160808b015184870152848b0151838701526200069b6101a08c0162000506565b82870152620006ae6101c08c0162000506565b90860152509699959850939650909450505050565b815163ffffffff16815261018081016020830151620006ea602084018263ffffffff169052565b50604083015162000702604084018262ffffff169052565b5060608301516200071b606084018263ffffffff169052565b50608083015162000733608084018262ffffff169052565b5060a08301516200074a60a084018261ffff169052565b5060c08301516200076660c08401826001600160601b03169052565b5060e08301516200077f60e084018263ffffffff169052565b5061010083810151908301526101208084015190830152610140808401516001600160a01b03908116918401919091526101609384015116929091019190915290565b60405161018081016001600160401b0381118282101715620007f457634e487b7160e01b600052604160045260246000fd5b60405290565b60805160601c60a05160601c60c05160601c615f2f620008796000396000818161042401526142b5015260008181610575015261439601526000818161030401528181610e100152818161113c0152818161198d01528181611d1801528181611e0c015281816122040152818161258201526126150152615f2f6000f3fe608060405234801561001057600080fd5b506004361061025c5760003560e01c806393f0c1fc11610145578063b7fdb436116100bd578063da5c67411161008c578063ef47a0ce11610071578063ef47a0ce1461066a578063f2fde38b1461067d578063faa3e9961461069057600080fd5b8063da5c674114610636578063eb5dcd6c1461065757600080fd5b8063b7fdb436146105c5578063c41b813a146105d8578063c7c3a19a146105fc578063c80480221461062357600080fd5b8063a72aa27e11610114578063b121e147116100f9578063b121e14714610597578063b657bc9c146105aa578063b79550be146105bd57600080fd5b8063a72aa27e1461055d578063ad1783611461057057600080fd5b806393f0c1fc146104f4578063948108f714610524578063a4c0ed3614610537578063a710b2211461054a57600080fd5b80635c975abb116101d85780637d9b97e0116101a757806385c1b0ba1161018c57806385c1b0ba146104b05780638da5cb5b146104c35780638e86139b146104e157600080fd5b80637d9b97e0146104a05780638456cb59146104a857600080fd5b80635c975abb1461045b578063744bfe611461047257806379ba5097146104855780637bbaf1ea1461048d57600080fd5b80631b6b6d231161022f5780633f4ba83a116102145780633f4ba83a146104175780634584a4191461041f57806348013d7b1461044657600080fd5b80631b6b6d23146102ff5780631e12b8a51461034b57600080fd5b806306e3b63214610261578063181f5a771461028a5780631865c57d146102d3578063187256e8146102ea575b600080fd5b61027461026f3660046153b3565b6106d6565b60405161028191906158b1565b60405180910390f35b6102c66040518060400160405280601481526020017f4b6565706572526567697374727920312e322e3000000000000000000000000081525081565b60405161028191906158f5565b6102db6107d2565b60405161028193929190615a82565b6102fd6102f8366004614e90565b610a8a565b005b6103267f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610281565b6103d7610359366004614e42565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff1692810183905260019091015460ff16151592018290529192909190565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845291151560208401526bffffffffffffffffffffffff1690820152606001610281565b6102fd610afb565b6103267f000000000000000000000000000000000000000000000000000000000000000081565b61044e600081565b6040516102819190615a38565b60035460ff165b6040519015158152602001610281565b6102fd610480366004615344565b610b0d565b6102fd610e99565b61046261049b366004615367565b610f9b565b6102fd611064565b6102fd6111d2565b6102fd6104be366004614ffb565b6111e2565b60005473ffffffffffffffffffffffffffffffffffffffff16610326565b6102fd6104ef36600461519c565b6119be565b610507610502366004615312565b611bbe565b6040516bffffffffffffffffffffffff9091168152602001610281565b6102fd6105323660046153f8565b611bf2565b6102fd610545366004614ecb565b611df4565b6102fd610558366004614e5d565b611fef565b6102fd61056b3660046153d5565b612289565b6103267f000000000000000000000000000000000000000000000000000000000000000081565b6102fd6105a5366004614e42565b612430565b6105076105b8366004615312565b612528565b6102fd612549565b6102fd6105d3366004614f9b565b6126b4565b6105eb6105e6366004615344565b612a15565b604051610281959493929190615908565b61060f61060a366004615312565b612cca565b6040516102819897969594939291906156a7565b6102fd610631366004615312565b612e55565b610649610644366004614f25565b61304b565b604051908152602001610281565b6102fd610665366004614e5d565b613242565b6102fd610678366004615234565b6133a1565b6102fd61068b366004614e42565b6136ed565b6106c961069e366004614e42565b73ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205460ff1690565b6040516102819190615a1e565b606060006106e46005613701565b905080841061071f576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826107315761072e8482615d16565b92505b60008367ffffffffffffffff81111561074c5761074c615ef3565b604051908082528060200260200182016040528015610775578160200160208202803683370190505b50905060005b848110156107c7576107986107908288615c56565b60059061370b565b8282815181106107aa576107aa615ec4565b6020908102919091010152806107bf81615dda565b91505061077b565b509150505b92915050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526040805161012081018252600c5463ffffffff8082168352640100000000808304821660208086019190915262ffffff6801000000000000000085048116868801526b010000000000000000000000850484166060878101919091526f010000000000000000000000000000008604909116608087015261ffff720100000000000000000000000000000000000086041660a08701526bffffffffffffffffffffffff74010000000000000000000000000000000000000000909504851660c0870152600d5480851660e0880152929092049092166101008501819052875260105490921690860152601154928501929092526109546005613701565b606080860191909152815163ffffffff908116855260208084015182168187015260408085015162ffffff90811682890152858501518416948801949094526080808601519094169387019390935260a08085015161ffff169087015260c0808501516bffffffffffffffffffffffff169087015260e08085015190921691860191909152600e54610100860152600f5461012086015260125473ffffffffffffffffffffffffffffffffffffffff90811661014087015260135416610160860152600480548351818402810184019094528084528793879390918391830182828015610a7757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610a4c575b5050505050905093509350935050909192565b610a9261371e565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836003811115610af257610af2615e66565b02179055505050565b610b0361371e565b610b0b61379f565b565b8073ffffffffffffffffffffffffffffffffffffffff8116610b5b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206002015483906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610bcd576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600760205260409020600101544364010000000090910467ffffffffffffffff161115610c2b576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600085815260076020526040812080546002909101546bffffffffffffffffffffffff740100000000000000000000000000000000000000009094048416939182169291169083821015610caf57610c868285615d2d565b9050826bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610caf5750815b6000610cbb8285615d2d565b60008a815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055601054909150610d0e9083906bffffffffffffffffffffffff16615c6e565b601080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154610d5691831690615d16565b601155604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8a1660208201528a917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a26040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff89811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044015b602060405180830381600087803b158015610e5557600080fd5b505af1158015610e69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8d9190615133565b50505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000610fa960035460ff1690565b15611010576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610f16565b61105c611057338686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250613880915050565b61397a565b949350505050565b61106c61371e565b6010546011546bffffffffffffffffffffffff9091169061108e908290615d16565b601155601080547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b602060405180830381600087803b15801561119657600080fd5b505af11580156111aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ce9190615133565b5050565b6111da61371e565b610b0b613dfe565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152600b602052604090205460ff16600381111561121e5761121e615e66565b141580156112665750600373ffffffffffffffffffffffffffffffffffffffff82166000908152600b602052604090205460ff16600381111561126357611263615e66565b14155b1561129d576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60125473ffffffffffffffffffffffffffffffffffffffff166112ec576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81611323576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff81111561137757611377615ef3565b6040519080825280602002602001820160405280156113aa57816020015b60608152602001906001900390816113955790505b50905060008667ffffffffffffffff8111156113c8576113c8615ef3565b60405190808252806020026020018201604052801561144d57816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816113e65790505b50905060005b8781101561174d5788888281811061146d5761146d615ec4565b60209081029290920135600081815260078452604090819020815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811698840198909852600184015463ffffffff81169584019590955267ffffffffffffffff6401000000008604166060840152938190048716608083015260029092015492831660a0820152910490931660c08401819052909850919650503314611560576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015167ffffffffffffffff908116146115a8576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848282815181106115bb576115bb615ec4565b6020026020010181905250600a600087815260200190815260200160002080546115e490615d86565b80601f016020809104026020016040519081016040528092919081815260200182805461161090615d86565b801561165d5780601f106116325761010080835404028352916020019161165d565b820191906000526020600020905b81548152906001019060200180831161164057829003601f168201915b505050505083828151811061167457611674615ec4565b60209081029190910101528451611699906bffffffffffffffffffffffff1685615c56565b600087815260076020908152604080832083815560018101849055600201839055600a90915281209195506116ce91906149a9565b6116d9600587613ebe565b508451604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8916602083015287917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28061174581615dda565b915050611453565b508260115461175c9190615d16565b601155604051600090611779908a908a9085908790602001615763565b60405160208183030381529060405290508673ffffffffffffffffffffffffffffffffffffffff16638e86139b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60008b73ffffffffffffffffffffffffffffffffffffffff166348013d7b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561182c57600080fd5b505afa158015611840573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118649190615213565b866040518463ffffffff1660e01b815260040161188393929190615a46565b60006040518083038186803b15801561189b57600080fd5b505afa1580156118af573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526118f591908101906151de565b6040518263ffffffff1660e01b815260040161191191906158f5565b600060405180830381600087803b15801561192b57600080fd5b505af115801561193f573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152602482018890527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb9150604401610e3b565b6002336000908152600b602052604090205460ff1660038111156119e4576119e4615e66565b14158015611a1657506003336000908152600b602052604090205460ff166003811115611a1357611a13615e66565b14155b15611a4d576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611a5d8486018661504f565b92509250925060005b8351811015611bb657611b23848281518110611a8457611a84615ec4565b6020026020010151848381518110611a9e57611a9e615ec4565b602002602001015160800151858481518110611abc57611abc615ec4565b602002602001015160400151868581518110611ada57611ada615ec4565b602002602001015160c00151878681518110611af857611af8615ec4565b602002602001015160000151878781518110611b1657611b16615ec4565b6020026020010151613eca565b838181518110611b3557611b35615ec4565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71848381518110611b7057611b70615ec4565b60209081029190910181015151604080516bffffffffffffffffffffffff909216825233928201929092520160405180910390a280611bae81615dda565b915050611a66565b505050505050565b6000806000611bcb614282565b915091506000611bdc83600061447d565b9050611be98582846144c2565b95945050505050565b6000828152600760205260409020600101548290640100000000900467ffffffffffffffff90811614611c51576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260076020526040902054611c799083906bffffffffffffffffffffffff16615c6e565b600084815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154611ccd91841690615c56565b6011556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b158015611d7157600080fd5b505af1158015611d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da99190615133565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611e63576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114611e9d576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611eab82840184615312565b600081815260076020526040902060010154909150640100000000900467ffffffffffffffff90811614611f0b576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040902054611f339085906bffffffffffffffffffffffff16615c6e565b600082815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff92909216919091179055601154611f8a908590615c56565b6011556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b8073ffffffffffffffffffffffffffffffffffffffff811661203d576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16928101929092526001015460ff161515918101919091529033146120ee576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600860209081526040909120805490921690915581015160115461213d916bffffffffffffffffffffffff1690615d16565b60115560208082015160405133815273ffffffffffffffffffffffffffffffffffffffff808716936bffffffffffffffffffffffff90931692908816917f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698910160405180910390a460208101516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526bffffffffffffffffffffffff90921660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b15801561224a57600080fd5b505af115801561225e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122829190615133565b5050505050565b6000828152600760205260409020600101548290640100000000900467ffffffffffffffff908116146122e8576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206002015483906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16331461235a576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8363ffffffff16108061237b5750600d5463ffffffff908116908416115b156123b2576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526007602090815260409182902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8716908117909155915191825285917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a250505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260096020526040902054163314612490576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526008602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556009909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b6000818152600760205260408120600101546107cc9063ffffffff16611bbe565b61255161371e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b1580156125d957600080fd5b505afa1580156125ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612611919061532b565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb336011548461265e9190615d16565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9092166004830152602482015260440161117c565b6126bc61371e565b82811415806126cb5750600283105b15612702576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60045481101561278e5760006004828154811061272457612724615ec4565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168252600890526040902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055508061278681615dda565b915050612705565b5060005b838110156129c45760008585838181106127ae576127ae615ec4565b90506020020160208101906127c39190614e42565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526008602052604081208054939450929091169086868681811061280557612805615ec4565b905060200201602081019061281a9190614e42565b905073ffffffffffffffffffffffffffffffffffffffff811615806128ad575073ffffffffffffffffffffffffffffffffffffffff82161580159061288b57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b80156128ad575073ffffffffffffffffffffffffffffffffffffffff81811614155b156128e4576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183015460ff1615612923576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905573ffffffffffffffffffffffffffffffffffffffff818116146129ad5782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783555b5050505080806129bc90615dda565b915050612792565b506129d1600485856149e3565b507f056264c94f28bb06c99d13f0446eb96c67c215d8d707bce2655a98ddf1c0b71f84848484604051612a079493929190615731565b60405180910390a150505050565b6060600080600080612a2561459f565b6000878152600760209081526040808320815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684880152600185015463ffffffff81168588015267ffffffffffffffff64010000000082041660608601528390048116608085015260029094015490811660a08401520490911660c08201528a8452600a90925280832090519192917f6e04ff0d0000000000000000000000000000000000000000000000000000000091612b059160240161593f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600080836080015173ffffffffffffffffffffffffffffffffffffffff16600c600001600b9054906101000a900463ffffffff1663ffffffff1684604051612bac919061568b565b60006040518083038160008787f1925050503d8060008114612bea576040519150601f19603f3d011682016040523d82523d6000602084013e612bef565b606091505b509150915081612c2d57806040517f96c36235000000000000000000000000000000000000000000000000000000008152600401610f1691906158f5565b80806020019051810190612c41919061514e565b9950915081612c7c576040517f865676e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612c8b8b8d8c6000613880565b9050612ca085826000015183606001516145d7565b6060810151608082015160a083015160c0909301519b9e919d509b50909998509650505050505050565b6000818152600760209081526040808320815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000928390048116848801908152600186015463ffffffff811686890181905267ffffffffffffffff64010000000083041660608881019182529287900485166080890181905260029099015495861660a089019081529690950490931660c087019081528b8b52600a9099529689208551915198519351945181548b9a8b998a998a998a998a9992989397929692959394939092908690612db990615d86565b80601f0160208091040260200160405190810160405280929190818152602001828054612de590615d86565b8015612e325780601f10612e0757610100808354040283529160200191612e32565b820191906000526020600020905b815481529060010190602001808311612e1557829003601f168201915b505050505095509850985098509850985098509850985050919395975091939597565b60008181526007602052604081206001015467ffffffffffffffff6401000000009091048116919082141590612ea060005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050818015612ef05750808015612eee5750438367ffffffffffffffff16115b155b15612f27576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015612f6c57506000848152600760205260409020600201546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15612fa3576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4381612fb757612fb4603282615c56565b90505b600085815260076020526040902060010180547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff1664010000000067ffffffffffffffff84160217905561300c600586613ebe565b5060405167ffffffffffffffff82169086907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a35050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff16331480159061308c575060135473ffffffffffffffffffffffffffffffffffffffff163314155b156130c3576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6130ce600143615d16565b600d5460408051924060208401523060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690830152640100000000900460e01b7fffffffff000000000000000000000000000000000000000000000000000000001660548201526058016040516020818303038152906040528051906020012060001c905061319b81878787600088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613eca92505050565b600d8054640100000000900463ffffffff169060046131b983615e13565b91906101000a81548163ffffffff021916908363ffffffff16021790555050807fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012868660405161323192919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a295945050505050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600860205260409020541633146132a2576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314156132f2576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600960205260409020548116908216146111ce5773ffffffffffffffffffffffffffffffffffffffff82811660008181526009602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b6133a961371e565b600d5460e082015163ffffffff918216911610156133f3576040517f39abc10400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516bffffffffffffffffffffffff1681526020018260e0015163ffffffff168152602001600c60010160049054906101000a900463ffffffff1663ffffffff16815250600c60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600e81905550806101200151600f81905550806101400151601260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806101600151601360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de325816040516136e29190615a73565b60405180910390a150565b6136f561371e565b6136fe816146f1565b50565b60006107cc825490565b600061371783836147e7565b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610f16565b60035460ff1661380b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610f16565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6138d66040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206001015463ffffffff1690806138f8614282565b915091506000613908838761447d565b905060006139178583856144c2565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff8d168152602081018c90529081018a90526bffffffffffffffffffffffff909116606082015260808101959095525060a084015260c0830152509050949350505050565b60006002805414156139e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f16565b60028055602082810151600081815260079092526040909120600101544364010000000090910467ffffffffffffffff1611613a50576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602080840151600090815260078252604090819020815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811696840196909652600184015463ffffffff81169584019590955267ffffffffffffffff640100000000860416606080850191909152948290048616608084015260029093015492831660a083015290910490921660c0830152845190850151613b149183916145d7565b60005a90506000634585e33b60e01b8660400151604051602401613b3891906158f5565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050613baa8660800151846080015183614811565b94505a613bb79083615d16565b91506000613bce838860a001518960c001516144c2565b602080890151600090815260079091526040902054909150613bff9082906bffffffffffffffffffffffff16615d2d565b6020888101805160009081526007909252604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff95861617905590518252902060020154613c6291839116615c6e565b60208881018051600090815260078352604080822060020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9687161790558b5192518252808220805486166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff958616021790558b5190921681526008909252902054613d1b91839174010000000000000000000000000000000000000000900416615c6e565b60086000896000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550866000015173ffffffffffffffffffffffffffffffffffffffff1686151588602001517fcaacad83e47cc45c280d487ec84184eee2fa3b54ebaa393bda7549f13da228f6848b60400151604051613de7929190615b29565b60405180910390a450505050506001600255919050565b60035460ff1615613e6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610f16565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586138563390565b6000613717838361485d565b60035460ff1615613f37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610f16565b73ffffffffffffffffffffffffffffffffffffffff85163b613f85576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8463ffffffff161080613fa65750600d5463ffffffff908116908516115b15613fdd576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518060e00160405280836bffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020018563ffffffff16815260200167ffffffffffffffff801681526020018673ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152506007600088815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160046101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550608082015181600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160020160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060c082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050816bffffffffffffffffffffffff1660115461424b9190615c56565b6011556000868152600a60209081526040909120825161426d92840190614a6b565b50614279600587614950565b50505050505050565b6000806000600c600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561431957600080fd5b505afa15801561432d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614351919061541b565b509450909250849150508015614375575061436c8242615d16565b8463ffffffff16105b80614381575060008113155b1561439057600e549550614394565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156143fa57600080fd5b505afa15801561440e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614432919061541b565b509450909250849150508015614456575061444d8242615d16565b8463ffffffff16105b80614462575060008113155b1561447157600f549450614475565b8094505b505050509091565b600c546000906144a7907201000000000000000000000000000000000000900461ffff1684615cd9565b90508180156144b55750803a105b156107cc57503a92915050565b6000806144d26201388086615c56565b6144dc9085615cd9565b600c549091506000906144f99063ffffffff16633b9aca00615c56565b600c5490915060009061451f90640100000000900463ffffffff1664e8d4a51000615cd9565b858361452f86633b9aca00615cd9565b6145399190615cd9565b6145439190615c9e565b61454d9190615c56565b90506b033b2e3c9fd0803ce8000000811115614595576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9695505050505050565b3215610b0b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff16614639576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff16811115614682576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff1614156146ec576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b73ffffffffffffffffffffffffffffffffffffffff8116331415614771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610f16565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008260000182815481106147fe576147fe615ec4565b9060005260206000200154905092915050565b60005a61138881101561482357600080fd5b61138881039050846040820482031161483b57600080fd5b50823b61484757600080fd5b60008083516020850160008789f1949350505050565b60008181526001830160205260408120548015614946576000614881600183615d16565b855490915060009061489590600190615d16565b90508181146148fa5760008660000182815481106148b5576148b5615ec4565b90600052602060002001549050808760000184815481106148d8576148d8615ec4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061490b5761490b615e95565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107cc565b60009150506107cc565b6000818152600183016020526040812054613717908490849084906149a1575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107cc565b5060006107cc565b5080546149b590615d86565b6000825580601f106149c5575050565b601f0160209004906000526020600020908101906136fe9190614adf565b828054828255906000526020600020908101928215614a5b579160200282015b82811115614a5b5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190614a03565b50614a67929150614adf565b5090565b828054614a7790615d86565b90600052602060002090601f016020900481019282614a995760008555614a5b565b82601f10614ab257805160ff1916838001178555614a5b565b82800160010185558215614a5b579182015b82811115614a5b578251825591602001919060010190614ac4565b5b80821115614a675760008155600101614ae0565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b1857600080fd5b919050565b60008083601f840112614b2f57600080fd5b50813567ffffffffffffffff811115614b4757600080fd5b6020830191508360208260051b8501011115614b6257600080fd5b9250929050565b600082601f830112614b7a57600080fd5b81356020614b8f614b8a83615bec565b615b9d565b80838252828201915082860187848660051b8901011115614baf57600080fd5b60005b85811015614c2f57813567ffffffffffffffff811115614bd157600080fd5b8801603f81018a13614be257600080fd5b858101356040614bf4614b8a83615c10565b8281528c82848601011115614c0857600080fd5b828285018a8301376000928101890192909252508552509284019290840190600101614bb2565b5090979650505050505050565b600082601f830112614c4d57600080fd5b81356020614c5d614b8a83615bec565b8281528181019085830160e080860288018501891015614c7c57600080fd5b60005b86811015614d2e5781838b031215614c9657600080fd5b614c9e615b50565b614ca784614e26565b8152614cb4878501614af4565b878201526040614cc5818601614df8565b9082015260608481013567ffffffffffffffff81168114614ce557600080fd5b908201526080614cf6858201614af4565b9082015260a0614d07858201614e26565b9082015260c0614d18858201614af4565b9082015285529385019391810191600101614c7f565b509198975050505050505050565b80518015158114614b1857600080fd5b60008083601f840112614d5e57600080fd5b50813567ffffffffffffffff811115614d7657600080fd5b602083019150836020828501011115614b6257600080fd5b600082601f830112614d9f57600080fd5b8151614dad614b8a82615c10565b818152846020838601011115614dc257600080fd5b61105c826020830160208701615d5a565b803561ffff81168114614b1857600080fd5b803562ffffff81168114614b1857600080fd5b803563ffffffff81168114614b1857600080fd5b805169ffffffffffffffffffff81168114614b1857600080fd5b80356bffffffffffffffffffffffff81168114614b1857600080fd5b600060208284031215614e5457600080fd5b61371782614af4565b60008060408385031215614e7057600080fd5b614e7983614af4565b9150614e8760208401614af4565b90509250929050565b60008060408385031215614ea357600080fd5b614eac83614af4565b9150602083013560048110614ec057600080fd5b809150509250929050565b60008060008060608587031215614ee157600080fd5b614eea85614af4565b935060208501359250604085013567ffffffffffffffff811115614f0d57600080fd5b614f1987828801614d4c565b95989497509550505050565b600080600080600060808688031215614f3d57600080fd5b614f4686614af4565b9450614f5460208701614df8565b9350614f6260408701614af4565b9250606086013567ffffffffffffffff811115614f7e57600080fd5b614f8a88828901614d4c565b969995985093965092949392505050565b60008060008060408587031215614fb157600080fd5b843567ffffffffffffffff80821115614fc957600080fd5b614fd588838901614b1d565b90965094506020870135915080821115614fee57600080fd5b50614f1987828801614b1d565b60008060006040848603121561501057600080fd5b833567ffffffffffffffff81111561502757600080fd5b61503386828701614b1d565b9094509250615046905060208501614af4565b90509250925092565b60008060006060848603121561506457600080fd5b833567ffffffffffffffff8082111561507c57600080fd5b818601915086601f83011261509057600080fd5b813560206150a0614b8a83615bec565b8083825282820191508286018b848660051b89010111156150c057600080fd5b600096505b848710156150e35780358352600196909601959183019183016150c5565b50975050870135925050808211156150fa57600080fd5b61510687838801614c3c565b9350604086013591508082111561511c57600080fd5b5061512986828701614b69565b9150509250925092565b60006020828403121561514557600080fd5b61371782614d3c565b6000806040838503121561516157600080fd5b61516a83614d3c565b9150602083015167ffffffffffffffff81111561518657600080fd5b61519285828601614d8e565b9150509250929050565b600080602083850312156151af57600080fd5b823567ffffffffffffffff8111156151c657600080fd5b6151d285828601614d4c565b90969095509350505050565b6000602082840312156151f057600080fd5b815167ffffffffffffffff81111561520757600080fd5b61105c84828501614d8e565b60006020828403121561522557600080fd5b81516003811061371757600080fd5b6000610180828403121561524757600080fd5b61524f615b79565b61525883614df8565b815261526660208401614df8565b602082015261527760408401614de5565b604082015261528860608401614df8565b606082015261529960808401614de5565b60808201526152aa60a08401614dd3565b60a08201526152bb60c08401614e26565b60c08201526152cc60e08401614df8565b60e0820152610100838101359082015261012080840135908201526101406152f5818501614af4565b90820152610160615307848201614af4565b908201529392505050565b60006020828403121561532457600080fd5b5035919050565b60006020828403121561533d57600080fd5b5051919050565b6000806040838503121561535757600080fd5b82359150614e8760208401614af4565b60008060006040848603121561537c57600080fd5b83359250602084013567ffffffffffffffff81111561539a57600080fd5b6153a686828701614d4c565b9497909650939450505050565b600080604083850312156153c657600080fd5b50508035926020909101359150565b600080604083850312156153e857600080fd5b82359150614e8760208401614df8565b6000806040838503121561540b57600080fd5b82359150614e8760208401614e26565b600080600080600060a0868803121561543357600080fd5b61543c86614e0c565b945060208601519350604086015192506060860151915061545f60808701614e0c565b90509295509295909350565b8183526000602080850194508260005b858110156154b45773ffffffffffffffffffffffffffffffffffffffff6154a183614af4565b168752958201959082019060010161547b565b509495945050505050565b600081518084526020808501808196508360051b8101915082860160005b858110156155075782840389526154f5848351615514565b988501989350908401906001016154dd565b5091979650505050505050565b6000815180845261552c816020860160208601615d5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6003811061556e5761556e615e66565b9052565b805163ffffffff1682526020810151615593602084018263ffffffff169052565b5060408101516155aa604084018262ffffff169052565b5060608101516155c2606084018263ffffffff169052565b5060808101516155d9608084018262ffffff169052565b5060a08101516155ef60a084018261ffff169052565b5060c081015161560f60c08401826bffffffffffffffffffffffff169052565b5060e081015161562760e084018263ffffffff169052565b50610100818101519083015261012080820151908301526101408082015173ffffffffffffffffffffffffffffffffffffffff81168285015250506101608181015173ffffffffffffffffffffffffffffffffffffffff8116848301525b50505050565b6000825161569d818460208701615d5a565b9190910192915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b1660208501528160408501526156e48285018b615514565b6bffffffffffffffffffffffff998a16606086015297811660808501529590951660a08301525067ffffffffffffffff9290921660c083015290931660e090930192909252949350505050565b60408152600061574560408301868861546b565b828103602084015261575881858761546b565b979650505050505050565b60006060808352858184015260807f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87111561579e57600080fd5b8660051b808983870137808501905081810160008152602083878403018188015281895180845260a093508385019150828b01945060005b8181101561588d57855180516bffffffffffffffffffffffff1684528481015173ffffffffffffffffffffffffffffffffffffffff9081168686015260408083015163ffffffff16908601528982015167ffffffffffffffff168a8601528882015116888501528581015161585a878601826bffffffffffffffffffffffff169052565b5060c09081015173ffffffffffffffffffffffffffffffffffffffff16908401529483019460e0909201916001016157d6565b505087810360408901526158a1818a6154bf565b9c9b505050505050505050505050565b6020808252825182820181905260009190848201906040850190845b818110156158e9578351835292840192918401916001016158cd565b50909695505050505050565b6020815260006137176020830184615514565b60a08152600061591b60a0830188615514565b90508560208301528460408301528360608301528260808301529695505050505050565b600060208083526000845481600182811c91508083168061596157607f831692505b858310811415615998577f4e487b710000000000000000000000000000000000000000000000000000000085526022600452602485fd5b8786018381526020018180156159b557600181146159e457615a0f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861682528782019650615a0f565b60008b81526020902060005b86811015615a09578154848201529085019089016159f0565b83019750505b50949998505050505050505050565b6020810160048310615a3257615a32615e66565b91905290565b602081016107cc828461555e565b615a50818561555e565b615a5d602082018461555e565b606060408201526000611be96060830184615514565b61018081016107cc8284615572565b600061022080830163ffffffff875116845260206bffffffffffffffffffffffff8189015116818601526040880151604086015260608801516060860152615acd6080860188615572565b6102008501929092528451908190526102408401918086019160005b81811015615b1b57835173ffffffffffffffffffffffffffffffffffffffff1685529382019392820192600101615ae9565b509298975050505050505050565b6bffffffffffffffffffffffff8316815260406020820152600061105c6040830184615514565b60405160e0810167ffffffffffffffff81118282101715615b7357615b73615ef3565b60405290565b604051610180810167ffffffffffffffff81118282101715615b7357615b73615ef3565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615be457615be4615ef3565b604052919050565b600067ffffffffffffffff821115615c0657615c06615ef3565b5060051b60200190565b600067ffffffffffffffff821115615c2a57615c2a615ef3565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008219821115615c6957615c69615e37565b500190565b60006bffffffffffffffffffffffff808316818516808303821115615c9557615c95615e37565b01949350505050565b600082615cd4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615d1157615d11615e37565b500290565b600082821015615d2857615d28615e37565b500390565b60006bffffffffffffffffffffffff83811690831681811015615d5257615d52615e37565b039392505050565b60005b83811015615d75578181015183820152602001615d5d565b838111156156855750506000910152565b600181811c90821680615d9a57607f821691505b60208210811415615dd4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615e0c57615e0c615e37565b5060010190565b600063ffffffff80831681811415615e2d57615e2d615e37565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60e06040523480156200001157600080fd5b50604051620066f2380380620066f2833981016040819052620000349162000577565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000107565b50506001600255506003805460ff191690556001600160601b0319606085811b821660805284811b821660a05283901b1660c052620000fd81620001b3565b50505050620007fa565b6001600160a01b038116331415620001625760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001bd620004a8565b600d5460e082015163ffffffff91821691161015620001ef57604051630e6af04160e21b815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516001600160601b031681526020018260e0015163ffffffff168152602001600c60010160049054906101000a900463ffffffff1663ffffffff16815250600c60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600e81905550806101200151600f81905550806101400151601260006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806101600151601360006101000a8154816001600160a01b0302191690836001600160a01b031602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de325816040516200049d9190620006c3565b60405180910390a150565b6000546001600160a01b03163314620005045760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b80516001600160a01b03811681146200051e57600080fd5b919050565b805161ffff811681146200051e57600080fd5b805162ffffff811681146200051e57600080fd5b805163ffffffff811681146200051e57600080fd5b80516001600160601b03811681146200051e57600080fd5b6000806000808486036101e08112156200059057600080fd5b6200059b8662000506565b9450620005ab6020870162000506565b9350620005bb6040870162000506565b925061018080605f1983011215620005d257600080fd5b620005dc620007c2565b9150620005ec606088016200054a565b8252620005fc608088016200054a565b60208301526200060f60a0880162000536565b60408301526200062260c088016200054a565b60608301526200063560e0880162000536565b60808301526101006200064a81890162000523565b60a08401526101206200065f818a016200055f565b60c085015261014062000674818b016200054a565b60e0860152610160808b015184870152848b0151838701526200069b6101a08c0162000506565b82870152620006ae6101c08c0162000506565b90860152509699959850939650909450505050565b815163ffffffff16815261018081016020830151620006ea602084018263ffffffff169052565b50604083015162000702604084018262ffffff169052565b5060608301516200071b606084018263ffffffff169052565b50608083015162000733608084018262ffffff169052565b5060a08301516200074a60a084018261ffff169052565b5060c08301516200076660c08401826001600160601b03169052565b5060e08301516200077f60e084018263ffffffff169052565b5061010083810151908301526101208084015190830152610140808401516001600160a01b03908116918401919091526101609384015116929091019190915290565b60405161018081016001600160401b0381118282101715620007f457634e487b7160e01b600052604160045260246000fd5b60405290565b60805160601c60a05160601c60c05160601c615e7962000879600039600081816104240152614126015260008181610575015261420701526000818161030401528181610e10015281816110d10152818161192201528181611cad01528181611da1015281816121990152818161251701526125aa0152615e796000f3fe608060405234801561001057600080fd5b506004361061025c5760003560e01c806393f0c1fc11610145578063b7fdb436116100bd578063da5c67411161008c578063ef47a0ce11610071578063ef47a0ce1461066a578063f2fde38b1461067d578063faa3e9961461069057600080fd5b8063da5c674114610636578063eb5dcd6c1461065757600080fd5b8063b7fdb436146105c5578063c41b813a146105d8578063c7c3a19a146105fc578063c80480221461062357600080fd5b8063a72aa27e11610114578063b121e147116100f9578063b121e14714610597578063b657bc9c146105aa578063b79550be146105bd57600080fd5b8063a72aa27e1461055d578063ad1783611461057057600080fd5b806393f0c1fc146104f4578063948108f714610524578063a4c0ed3614610537578063a710b2211461054a57600080fd5b80635c975abb116101d85780637d9b97e0116101a757806385c1b0ba1161018c57806385c1b0ba146104b05780638da5cb5b146104c35780638e86139b146104e157600080fd5b80637d9b97e0146104a05780638456cb59146104a857600080fd5b80635c975abb1461045b578063744bfe611461047257806379ba5097146104855780637bbaf1ea1461048d57600080fd5b80631b6b6d231161022f5780633f4ba83a116102145780633f4ba83a146104175780634584a4191461041f57806348013d7b1461044657600080fd5b80631b6b6d23146102ff5780631e12b8a51461034b57600080fd5b806306e3b63214610261578063181f5a771461028a5780631865c57d146102d3578063187256e8146102ea575b600080fd5b61027461026f3660046152fd565b6106d6565b60405161028191906157fb565b60405180910390f35b6102c66040518060400160405280601481526020017f4b6565706572526567697374727920312e322e3000000000000000000000000081525081565b604051610281919061583f565b6102db6107d2565b604051610281939291906159cc565b6102fd6102f8366004614dda565b610a8a565b005b6103267f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610281565b6103d7610359366004614d8c565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff1692810183905260019091015460ff16151592018290529192909190565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845291151560208401526bffffffffffffffffffffffff1690820152606001610281565b6102fd610afb565b6103267f000000000000000000000000000000000000000000000000000000000000000081565b61044e600081565b6040516102819190615982565b60035460ff165b6040519015158152602001610281565b6102fd61048036600461528e565b610b0d565b6102fd610e99565b61046261049b3660046152b1565b610f9b565b6102fd610ff9565b6102fd611167565b6102fd6104be366004614f45565b611177565b60005473ffffffffffffffffffffffffffffffffffffffff16610326565b6102fd6104ef3660046150e6565b611953565b61050761050236600461525c565b611b53565b6040516bffffffffffffffffffffffff9091168152602001610281565b6102fd610532366004615342565b611b87565b6102fd610545366004614e15565b611d89565b6102fd610558366004614da7565b611f84565b6102fd61056b36600461531f565b61221e565b6103267f000000000000000000000000000000000000000000000000000000000000000081565b6102fd6105a5366004614d8c565b6123c5565b6105076105b836600461525c565b6124bd565b6102fd6124de565b6102fd6105d3366004614ee5565b612649565b6105eb6105e636600461528e565b6129aa565b604051610281959493929190615852565b61060f61060a36600461525c565b612c5f565b6040516102819897969594939291906155f1565b6102fd61063136600461525c565b612dea565b610649610644366004614e6f565b612fe0565b604051908152602001610281565b6102fd610665366004614da7565b6131d7565b6102fd61067836600461517e565b613336565b6102fd61068b366004614d8c565b613682565b6106c961069e366004614d8c565b73ffffffffffffffffffffffffffffffffffffffff166000908152600b602052604090205460ff1690565b6040516102819190615968565b606060006106e46005613696565b905080841061071f576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826107315761072e8482615c60565b92505b60008367ffffffffffffffff81111561074c5761074c615e3d565b604051908082528060200260200182016040528015610775578160200160208202803683370190505b50905060005b848110156107c7576107986107908288615ba0565b6005906136a0565b8282815181106107aa576107aa615e0e565b6020908102919091010152806107bf81615d24565b91505061077b565b509150505b92915050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526040805161012081018252600c5463ffffffff8082168352640100000000808304821660208086019190915262ffffff6801000000000000000085048116868801526b010000000000000000000000850484166060878101919091526f010000000000000000000000000000008604909116608087015261ffff720100000000000000000000000000000000000086041660a08701526bffffffffffffffffffffffff74010000000000000000000000000000000000000000909504851660c0870152600d5480851660e0880152929092049092166101008501819052875260105490921690860152601154928501929092526109546005613696565b606080860191909152815163ffffffff908116855260208084015182168187015260408085015162ffffff90811682890152858501518416948801949094526080808601519094169387019390935260a08085015161ffff169087015260c0808501516bffffffffffffffffffffffff169087015260e08085015190921691860191909152600e54610100860152600f5461012086015260125473ffffffffffffffffffffffffffffffffffffffff90811661014087015260135416610160860152600480548351818402810184019094528084528793879390918391830182828015610a7757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610a4c575b5050505050905093509350935050909192565b610a926136b3565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836003811115610af257610af2615db0565b02179055505050565b610b036136b3565b610b0b613734565b565b8073ffffffffffffffffffffffffffffffffffffffff8116610b5b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206002015483906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610bcd576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000848152600760205260409020600101544364010000000090910467ffffffffffffffff161115610c2b576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c54600085815260076020526040812080546002909101546bffffffffffffffffffffffff740100000000000000000000000000000000000000009094048416939182169291169083821015610caf57610c868285615c77565b9050826bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610caf5750815b6000610cbb8285615c77565b60008a815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055601054909150610d0e9083906bffffffffffffffffffffffff16615bb8565b601080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154610d5691831690615c60565b601155604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8a1660208201528a917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a26040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff89811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044015b602060405180830381600087803b158015610e5557600080fd5b505af1158015610e69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8d919061507d565b50505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000610fa56137b1565b610ff1610fec338686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061381e915050565b613918565b949350505050565b6110016136b3565b6010546011546bffffffffffffffffffffffff90911690611023908290615c60565b601155601080547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b602060405180830381600087803b15801561112b57600080fd5b505af115801561113f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611163919061507d565b5050565b61116f6136b3565b610b0b613d39565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152600b602052604090205460ff1660038111156111b3576111b3615db0565b141580156111fb5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152600b602052604090205460ff1660038111156111f8576111f8615db0565b14155b15611232576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60125473ffffffffffffffffffffffffffffffffffffffff16611281576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816112b8576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff81111561130c5761130c615e3d565b60405190808252806020026020018201604052801561133f57816020015b606081526020019060019003908161132a5790505b50905060008667ffffffffffffffff81111561135d5761135d615e3d565b6040519080825280602002602001820160405280156113e257816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161137b5790505b50905060005b878110156116e25788888281811061140257611402615e0e565b60209081029290920135600081815260078452604090819020815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811698840198909852600184015463ffffffff81169584019590955267ffffffffffffffff6401000000008604166060840152938190048716608083015260029092015492831660a0820152910490931660c084018190529098509196505033146114f5576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606085015167ffffffffffffffff9081161461153d576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8482828151811061155057611550615e0e565b6020026020010181905250600a6000878152602001908152602001600020805461157990615cd0565b80601f01602080910402602001604051908101604052809291908181526020018280546115a590615cd0565b80156115f25780601f106115c7576101008083540402835291602001916115f2565b820191906000526020600020905b8154815290600101906020018083116115d557829003601f168201915b505050505083828151811061160957611609615e0e565b6020908102919091010152845161162e906bffffffffffffffffffffffff1685615ba0565b600087815260076020908152604080832083815560018101849055600201839055600a909152812091955061166391906148f8565b61166e600587613d94565b508451604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8916602083015287917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a2806116da81615d24565b9150506113e8565b50826011546116f19190615c60565b60115560405160009061170e908a908a90859087906020016156ad565b60405160208183030381529060405290508673ffffffffffffffffffffffffffffffffffffffff16638e86139b601260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60008b73ffffffffffffffffffffffffffffffffffffffff166348013d7b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117c157600080fd5b505afa1580156117d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f9919061515d565b866040518463ffffffff1660e01b815260040161181893929190615990565b60006040518083038186803b15801561183057600080fd5b505afa158015611844573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261188a9190810190615128565b6040518263ffffffff1660e01b81526004016118a6919061583f565b600060405180830381600087803b1580156118c057600080fd5b505af11580156118d4573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152602482018890527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb9150604401610e3b565b6002336000908152600b602052604090205460ff16600381111561197957611979615db0565b141580156119ab57506003336000908152600b602052604090205460ff1660038111156119a8576119a8615db0565b14155b156119e2576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080806119f284860186614f99565b92509250925060005b8351811015611b4b57611ab8848281518110611a1957611a19615e0e565b6020026020010151848381518110611a3357611a33615e0e565b602002602001015160800151858481518110611a5157611a51615e0e565b602002602001015160400151868581518110611a6f57611a6f615e0e565b602002602001015160c00151878681518110611a8d57611a8d615e0e565b602002602001015160000151878781518110611aab57611aab615e0e565b6020026020010151613da0565b838181518110611aca57611aca615e0e565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71848381518110611b0557611b05615e0e565b60209081029190910181015151604080516bffffffffffffffffffffffff909216825233928201929092520160405180910390a280611b4381615d24565b9150506119fb565b505050505050565b6000806000611b606140f3565b915091506000611b718360006142ee565b9050611b7e858284614333565b95945050505050565b6000828152600760205260409020600101548290640100000000900467ffffffffffffffff90811614611be6576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083815260076020526040902054611c0e9083906bffffffffffffffffffffffff16615bb8565b600084815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff928316179055601154611c6291841690615ba0565b6011556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401602060405180830381600087803b158015611d0657600080fd5b505af1158015611d1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3e919061507d565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611df8576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114611e32576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611e408284018461525c565b600081815260076020526040902060010154909150640100000000900467ffffffffffffffff90811614611ea0576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040902054611ec89085906bffffffffffffffffffffffff16615bb8565b600082815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff92909216919091179055601154611f1f908590615ba0565b6011556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b8073ffffffffffffffffffffffffffffffffffffffff8116611fd2576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16928101929092526001015460ff16151591810191909152903314612083576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808516600090815260086020908152604090912080549092169091558101516011546120d2916bffffffffffffffffffffffff1690615c60565b60115560208082015160405133815273ffffffffffffffffffffffffffffffffffffffff808716936bffffffffffffffffffffffff90931692908816917f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698910160405180910390a460208101516040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526bffffffffffffffffffffffff90921660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b1580156121df57600080fd5b505af11580156121f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612217919061507d565b5050505050565b6000828152600760205260409020600101548290640100000000900467ffffffffffffffff9081161461227d576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206002015483906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146122ef576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8363ffffffff1610806123105750600d5463ffffffff908116908416115b15612347576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526007602090815260409182902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8716908117909155915191825285917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a250505050565b73ffffffffffffffffffffffffffffffffffffffff818116600090815260096020526040902054163314612425576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526008602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556009909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b6000818152600760205260408120600101546107cc9063ffffffff16611b53565b6124e66136b3565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b15801561256e57600080fd5b505afa158015612582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a69190615275565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33601154846125f39190615c60565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401611111565b6126516136b3565b82811415806126605750600283105b15612697576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600454811015612723576000600482815481106126b9576126b9615e0e565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168252600890526040902060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055508061271b81615d24565b91505061269a565b5060005b8381101561295957600085858381811061274357612743615e0e565b90506020020160208101906127589190614d8c565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526008602052604081208054939450929091169086868681811061279a5761279a615e0e565b90506020020160208101906127af9190614d8c565b905073ffffffffffffffffffffffffffffffffffffffff81161580612842575073ffffffffffffffffffffffffffffffffffffffff82161580159061282057508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015612842575073ffffffffffffffffffffffffffffffffffffffff81811614155b15612879576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183015460ff16156128b8576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600183810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905573ffffffffffffffffffffffffffffffffffffffff818116146129425782547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff82161783555b50505050808061295190615d24565b915050612727565b5061296660048585614932565b507f056264c94f28bb06c99d13f0446eb96c67c215d8d707bce2655a98ddf1c0b71f8484848460405161299c949392919061567b565b60405180910390a150505050565b60606000806000806129ba614410565b6000878152600760209081526040808320815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684880152600185015463ffffffff81168588015267ffffffffffffffff64010000000082041660608601528390048116608085015260029094015490811660a08401520490911660c08201528a8452600a90925280832090519192917f6e04ff0d0000000000000000000000000000000000000000000000000000000091612a9a91602401615889565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600080836080015173ffffffffffffffffffffffffffffffffffffffff16600c600001600b9054906101000a900463ffffffff1663ffffffff1684604051612b4191906155d5565b60006040518083038160008787f1925050503d8060008114612b7f576040519150601f19603f3d011682016040523d82523d6000602084013e612b84565b606091505b509150915081612bc257806040517f96c36235000000000000000000000000000000000000000000000000000000008152600401610f16919061583f565b80806020019051810190612bd69190615098565b9950915081612c11576040517f865676e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612c208b8d8c600061381e565b9050612c358582600001518360600151614448565b6060810151608082015160a083015160c0909301519b9e919d509b50909998509650505050505050565b6000818152600760209081526040808320815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000928390048116848801908152600186015463ffffffff811686890181905267ffffffffffffffff64010000000083041660608881019182529287900485166080890181905260029099015495861660a089019081529690950490931660c087019081528b8b52600a9099529689208551915198519351945181548b9a8b998a998a998a998a9992989397929692959394939092908690612d4e90615cd0565b80601f0160208091040260200160405190810160405280929190818152602001828054612d7a90615cd0565b8015612dc75780601f10612d9c57610100808354040283529160200191612dc7565b820191906000526020600020905b815481529060010190602001808311612daa57829003601f168201915b505050505095509850985098509850985098509850985050919395975091939597565b60008181526007602052604081206001015467ffffffffffffffff6401000000009091048116919082141590612e3560005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050818015612e855750808015612e835750438367ffffffffffffffff16115b155b15612ebc576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80158015612f0157506000848152600760205260409020600201546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314155b15612f38576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4381612f4c57612f49603282615ba0565b90505b600085815260076020526040902060010180547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff1664010000000067ffffffffffffffff841602179055612fa1600586613d94565b5060405167ffffffffffffffff82169086907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a35050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314801590613021575060135473ffffffffffffffffffffffffffffffffffffffff163314155b15613058576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613063600143615c60565b600d5460408051924060208401523060601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690830152640100000000900460e01b7fffffffff000000000000000000000000000000000000000000000000000000001660548201526058016040516020818303038152906040528051906020012060001c905061313081878787600088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613da092505050565b600d8054640100000000900463ffffffff1690600461314e83615d5d565b91906101000a81548163ffffffff021916908363ffffffff16021790555050807fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d01286866040516131c692919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a295945050505050565b73ffffffffffffffffffffffffffffffffffffffff828116600090815260086020526040902054163314613237576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331415613287576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600960205260409020548116908216146111635773ffffffffffffffffffffffffffffffffffffffff82811660008181526009602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b61333e6136b3565b600d5460e082015163ffffffff91821691161015613388576040517f39abc10400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516bffffffffffffffffffffffff1681526020018260e0015163ffffffff168152602001600c60010160049054906101000a900463ffffffff1663ffffffff16815250600c60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600e81905550806101200151600f81905550806101400151601260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806101600151601360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de3258160405161367791906159bd565b60405180910390a150565b61368a6136b3565b61369381614562565b50565b60006107cc825490565b60006136ac8383614658565b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610f16565b61373c614682565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60035460ff1615610b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610f16565b6138746040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206001015463ffffffff1690806138966140f3565b9150915060006138a683876142ee565b905060006138b5858385614333565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff8d168152602081018c90529081018a90526bffffffffffffffffffffffff909116606082015260808101959095525060a084015260c0830152509050949350505050565b60006139226146ee565b602082810151600081815260079092526040909120600101544364010000000090910467ffffffffffffffff1611613986576040517fd096219c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602080840151600090815260078252604090819020815160e08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811696840196909652600184015463ffffffff81169584019590955267ffffffffffffffff640100000000860416606080850191909152948290048616608084015260029093015492831660a083015290910490921660c0830152845190850151613a4a918391614448565b60005a90506000634585e33b60e01b8660400151604051602401613a6e919061583f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050613ae08660800151846080015183614760565b94505a613aed9083615c60565b91506000613b04838860a001518960c00151614333565b602080890151600090815260079091526040902054909150613b359082906bffffffffffffffffffffffff16615c77565b6020888101805160009081526007909252604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff95861617905590518252902060020154613b9891839116615bb8565b60208881018051600090815260078352604080822060020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9687161790558b5192518252808220805486166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff958616021790558b5190921681526008909252902054613c5191839174010000000000000000000000000000000000000000900416615bb8565b60086000896000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550866000015173ffffffffffffffffffffffffffffffffffffffff1686151588602001517fcaacad83e47cc45c280d487ec84184eee2fa3b54ebaa393bda7549f13da228f6848b60400151604051613d1d929190615a73565b60405180910390a45050505050613d346001600255565b919050565b613d416137b1565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586137873390565b60006136ac83836147ac565b613da86137b1565b73ffffffffffffffffffffffffffffffffffffffff85163b613df6576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc8463ffffffff161080613e175750600d5463ffffffff908116908516115b15613e4e576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518060e00160405280836bffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020018563ffffffff16815260200167ffffffffffffffff801681526020018673ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff168152506007600088815260200190815260200160002060008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160046101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550608082015181600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160020160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060c082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050816bffffffffffffffffffffffff166011546140bc9190615ba0565b6011556000868152600a6020908152604090912082516140de928401906149ba565b506140ea60058761489f565b50505050505050565b6000806000600c600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561418a57600080fd5b505afa15801561419e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c29190615365565b5094509092508491505080156141e657506141dd8242615c60565b8463ffffffff16105b806141f2575060008113155b1561420157600e549550614205565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561426b57600080fd5b505afa15801561427f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142a39190615365565b5094509092508491505080156142c757506142be8242615c60565b8463ffffffff16105b806142d3575060008113155b156142e257600f5494506142e6565b8094505b505050509091565b600c54600090614318907201000000000000000000000000000000000000900461ffff1684615c23565b90508180156143265750803a105b156107cc57503a92915050565b6000806143436201388086615ba0565b61434d9085615c23565b600c5490915060009061436a9063ffffffff16633b9aca00615ba0565b600c5490915060009061439090640100000000900463ffffffff1664e8d4a51000615c23565b85836143a086633b9aca00615c23565b6143aa9190615c23565b6143b49190615be8565b6143be9190615ba0565b90506b033b2e3c9fd0803ce8000000811115614406576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9695505050505050565b3215610b0b576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff166144aa576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff168111156144f3576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff16141561455d576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314156145e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610f16565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600082600001828154811061466f5761466f615e0e565b9060005260206000200154905092915050565b60035460ff16610b0b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610f16565b60028054141561475a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610f16565b60028055565b60005a61138881101561477257600080fd5b61138881039050846040820482031161478a57600080fd5b50823b61479657600080fd5b60008083516020850160008789f1949350505050565b600081815260018301602052604081205480156148955760006147d0600183615c60565b85549091506000906147e490600190615c60565b905081811461484957600086600001828154811061480457614804615e0e565b906000526020600020015490508087600001848154811061482757614827615e0e565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061485a5761485a615ddf565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107cc565b60009150506107cc565b60008181526001830160205260408120546136ac908490849084906148f0575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107cc565b5060006107cc565b50805461490490615cd0565b6000825580601f10614914575050565b601f0160209004906000526020600020908101906136939190614a2e565b8280548282559060005260206000209081019282156149aa579160200282015b828111156149aa5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190614952565b506149b6929150614a2e565b5090565b8280546149c690615cd0565b90600052602060002090601f0160209004810192826149e857600085556149aa565b82601f10614a0157805160ff19168380011785556149aa565b828001600101855582156149aa579182015b828111156149aa578251825591602001919060010190614a13565b5b808211156149b65760008155600101614a2f565b803573ffffffffffffffffffffffffffffffffffffffff81168114613d3457600080fd5b60008083601f840112614a7957600080fd5b50813567ffffffffffffffff811115614a9157600080fd5b6020830191508360208260051b8501011115614aac57600080fd5b9250929050565b600082601f830112614ac457600080fd5b81356020614ad9614ad483615b36565b615ae7565b80838252828201915082860187848660051b8901011115614af957600080fd5b60005b85811015614b7957813567ffffffffffffffff811115614b1b57600080fd5b8801603f81018a13614b2c57600080fd5b858101356040614b3e614ad483615b5a565b8281528c82848601011115614b5257600080fd5b828285018a8301376000928101890192909252508552509284019290840190600101614afc565b5090979650505050505050565b600082601f830112614b9757600080fd5b81356020614ba7614ad483615b36565b8281528181019085830160e080860288018501891015614bc657600080fd5b60005b86811015614c785781838b031215614be057600080fd5b614be8615a9a565b614bf184614d70565b8152614bfe878501614a43565b878201526040614c0f818601614d42565b9082015260608481013567ffffffffffffffff81168114614c2f57600080fd5b908201526080614c40858201614a43565b9082015260a0614c51858201614d70565b9082015260c0614c62858201614a43565b9082015285529385019391810191600101614bc9565b509198975050505050505050565b80518015158114613d3457600080fd5b60008083601f840112614ca857600080fd5b50813567ffffffffffffffff811115614cc057600080fd5b602083019150836020828501011115614aac57600080fd5b600082601f830112614ce957600080fd5b8151614cf7614ad482615b5a565b818152846020838601011115614d0c57600080fd5b610ff1826020830160208701615ca4565b803561ffff81168114613d3457600080fd5b803562ffffff81168114613d3457600080fd5b803563ffffffff81168114613d3457600080fd5b805169ffffffffffffffffffff81168114613d3457600080fd5b80356bffffffffffffffffffffffff81168114613d3457600080fd5b600060208284031215614d9e57600080fd5b6136ac82614a43565b60008060408385031215614dba57600080fd5b614dc383614a43565b9150614dd160208401614a43565b90509250929050565b60008060408385031215614ded57600080fd5b614df683614a43565b9150602083013560048110614e0a57600080fd5b809150509250929050565b60008060008060608587031215614e2b57600080fd5b614e3485614a43565b935060208501359250604085013567ffffffffffffffff811115614e5757600080fd5b614e6387828801614c96565b95989497509550505050565b600080600080600060808688031215614e8757600080fd5b614e9086614a43565b9450614e9e60208701614d42565b9350614eac60408701614a43565b9250606086013567ffffffffffffffff811115614ec857600080fd5b614ed488828901614c96565b969995985093965092949392505050565b60008060008060408587031215614efb57600080fd5b843567ffffffffffffffff80821115614f1357600080fd5b614f1f88838901614a67565b90965094506020870135915080821115614f3857600080fd5b50614e6387828801614a67565b600080600060408486031215614f5a57600080fd5b833567ffffffffffffffff811115614f7157600080fd5b614f7d86828701614a67565b9094509250614f90905060208501614a43565b90509250925092565b600080600060608486031215614fae57600080fd5b833567ffffffffffffffff80821115614fc657600080fd5b818601915086601f830112614fda57600080fd5b81356020614fea614ad483615b36565b8083825282820191508286018b848660051b890101111561500a57600080fd5b600096505b8487101561502d57803583526001969096019591830191830161500f565b509750508701359250508082111561504457600080fd5b61505087838801614b86565b9350604086013591508082111561506657600080fd5b5061507386828701614ab3565b9150509250925092565b60006020828403121561508f57600080fd5b6136ac82614c86565b600080604083850312156150ab57600080fd5b6150b483614c86565b9150602083015167ffffffffffffffff8111156150d057600080fd5b6150dc85828601614cd8565b9150509250929050565b600080602083850312156150f957600080fd5b823567ffffffffffffffff81111561511057600080fd5b61511c85828601614c96565b90969095509350505050565b60006020828403121561513a57600080fd5b815167ffffffffffffffff81111561515157600080fd5b610ff184828501614cd8565b60006020828403121561516f57600080fd5b8151600381106136ac57600080fd5b6000610180828403121561519157600080fd5b615199615ac3565b6151a283614d42565b81526151b060208401614d42565b60208201526151c160408401614d2f565b60408201526151d260608401614d42565b60608201526151e360808401614d2f565b60808201526151f460a08401614d1d565b60a082015261520560c08401614d70565b60c082015261521660e08401614d42565b60e08201526101008381013590820152610120808401359082015261014061523f818501614a43565b90820152610160615251848201614a43565b908201529392505050565b60006020828403121561526e57600080fd5b5035919050565b60006020828403121561528757600080fd5b5051919050565b600080604083850312156152a157600080fd5b82359150614dd160208401614a43565b6000806000604084860312156152c657600080fd5b83359250602084013567ffffffffffffffff8111156152e457600080fd5b6152f086828701614c96565b9497909650939450505050565b6000806040838503121561531057600080fd5b50508035926020909101359150565b6000806040838503121561533257600080fd5b82359150614dd160208401614d42565b6000806040838503121561535557600080fd5b82359150614dd160208401614d70565b600080600080600060a0868803121561537d57600080fd5b61538686614d56565b94506020860151935060408601519250606086015191506153a960808701614d56565b90509295509295909350565b8183526000602080850194508260005b858110156153fe5773ffffffffffffffffffffffffffffffffffffffff6153eb83614a43565b16875295820195908201906001016153c5565b509495945050505050565b600081518084526020808501808196508360051b8101915082860160005b8581101561545157828403895261543f84835161545e565b98850198935090840190600101615427565b5091979650505050505050565b60008151808452615476816020860160208601615ca4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600381106154b8576154b8615db0565b9052565b805163ffffffff16825260208101516154dd602084018263ffffffff169052565b5060408101516154f4604084018262ffffff169052565b50606081015161550c606084018263ffffffff169052565b506080810151615523608084018262ffffff169052565b5060a081015161553960a084018261ffff169052565b5060c081015161555960c08401826bffffffffffffffffffffffff169052565b5060e081015161557160e084018263ffffffff169052565b50610100818101519083015261012080820151908301526101408082015173ffffffffffffffffffffffffffffffffffffffff81168285015250506101608181015173ffffffffffffffffffffffffffffffffffffffff8116848301525b50505050565b600082516155e7818460208701615ca4565b9190910192915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808c16845263ffffffff8b16602085015281604085015261562e8285018b61545e565b6bffffffffffffffffffffffff998a16606086015297811660808501529590951660a08301525067ffffffffffffffff9290921660c083015290931660e090930192909252949350505050565b60408152600061568f6040830186886153b5565b82810360208401526156a28185876153b5565b979650505050505050565b60006060808352858184015260807f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8711156156e857600080fd5b8660051b808983870137808501905081810160008152602083878403018188015281895180845260a093508385019150828b01945060005b818110156157d757855180516bffffffffffffffffffffffff1684528481015173ffffffffffffffffffffffffffffffffffffffff9081168686015260408083015163ffffffff16908601528982015167ffffffffffffffff168a860152888201511688850152858101516157a4878601826bffffffffffffffffffffffff169052565b5060c09081015173ffffffffffffffffffffffffffffffffffffffff16908401529483019460e090920191600101615720565b505087810360408901526157eb818a615409565b9c9b505050505050505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561583357835183529284019291840191600101615817565b50909695505050505050565b6020815260006136ac602083018461545e565b60a08152600061586560a083018861545e565b90508560208301528460408301528360608301528260808301529695505050505050565b600060208083526000845481600182811c9150808316806158ab57607f831692505b8583108114156158e2577f4e487b710000000000000000000000000000000000000000000000000000000085526022600452602485fd5b8786018381526020018180156158ff576001811461592e57615959565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861682528782019650615959565b60008b81526020902060005b868110156159535781548482015290850190890161593a565b83019750505b50949998505050505050505050565b602081016004831061597c5761597c615db0565b91905290565b602081016107cc82846154a8565b61599a81856154a8565b6159a760208201846154a8565b606060408201526000611b7e606083018461545e565b61018081016107cc82846154bc565b600061022080830163ffffffff875116845260206bffffffffffffffffffffffff8189015116818601526040880151604086015260608801516060860152615a1760808601886154bc565b6102008501929092528451908190526102408401918086019160005b81811015615a6557835173ffffffffffffffffffffffffffffffffffffffff1685529382019392820192600101615a33565b509298975050505050505050565b6bffffffffffffffffffffffff83168152604060208201526000610ff1604083018461545e565b60405160e0810167ffffffffffffffff81118282101715615abd57615abd615e3d565b60405290565b604051610180810167ffffffffffffffff81118282101715615abd57615abd615e3d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715615b2e57615b2e615e3d565b604052919050565b600067ffffffffffffffff821115615b5057615b50615e3d565b5060051b60200190565b600067ffffffffffffffff821115615b7457615b74615e3d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60008219821115615bb357615bb3615d81565b500190565b60006bffffffffffffffffffffffff808316818516808303821115615bdf57615bdf615d81565b01949350505050565b600082615c1e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615c5b57615c5b615d81565b500290565b600082821015615c7257615c72615d81565b500390565b60006bffffffffffffffffffffffff83811690831681811015615c9c57615c9c615d81565b039392505050565b60005b83811015615cbf578181015183820152602001615ca7565b838111156155cf5750506000910152565b600181811c90821680615ce457607f821691505b60208210811415615d1e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615d5657615d56615d81565b5060010190565b600063ffffffff80831681811415615d7757615d77615d81565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var KeeperRegistryABI = KeeperRegistryMetaData.ABI diff --git a/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go b/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go index 326f08e4a90..73ff800e12b 100644 --- a/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go +++ b/core/gethwrappers/generated/keeper_registry_wrapper1_3/keeper_registry_wrapper1_3.go @@ -54,7 +54,7 @@ type State struct { var KeeperRegistryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"contractKeeperRegistryLogic1_3\",\"name\":\"keeperRegistryLogic\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ArrayHasNoEntries\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotCancel\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateEntry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GasLimitOutsideRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeepersMustTakeTurns\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyActiveKeepers\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByLINKToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrRegistrar\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByProposedPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"TargetCheckReverted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TranscoderNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"FundsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"FundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"KeepersUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"PayeeshipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"PaymentWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"UpkeepAdminTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"atBlockHeight\",\"type\":\"uint64\"}],\"name\":\"UpkeepCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"UpkeepCheckDataUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"gasLimit\",\"type\":\"uint96\"}],\"name\":\"UpkeepGasLimitSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"remainingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"UpkeepMigrated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepPaused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"UpkeepPerformed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startingBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"importedFrom\",\"type\":\"address\"}],\"name\":\"UpkeepReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"executeGas\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"UpkeepRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"UpkeepUnpaused\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"ARB_NITRO_ORACLE\",\"outputs\":[{\"internalType\":\"contractArbGasInfo\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FAST_GAS_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"KEEPER_REGISTRY_LOGIC\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OPTIMISM_ORACLE\",\"outputs\":[{\"internalType\":\"contractOVM_GasPriceOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PAYMENT_MODEL\",\"outputs\":[{\"internalType\":\"enumKeeperRegistryBase1_3.PaymentModel\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REGISTRY_GAS_OVERHEAD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"}],\"name\":\"acceptPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"acceptUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"cancelUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxLinkPayment\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"adjustedGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkEth\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveUpkeepIDs\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"getKeeperInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"getMaxPaymentForGas\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"maxPayment\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getMinBalanceForUpkeep\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"minBalance\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"enumKeeperRegistryBase1_3.MigrationPermission\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nonce\",\"type\":\"uint32\"},{\"internalType\":\"uint96\",\"name\":\"ownerLinkBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint256\",\"name\":\"expectedLinkBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numUpkeeps\",\"type\":\"uint256\"}],\"internalType\":\"structState\",\"name\":\"state\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getUpkeep\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"executeGas\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"lastKeeper\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"maxValidBlocknumber\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"amountSpent\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"paused\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"ids\",\"type\":\"uint256[]\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"migrateUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"pauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedUpkeeps\",\"type\":\"bytes\"}],\"name\":\"receiveUpkeeps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"paymentPremiumPPB\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"flatFeeMicroLink\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"blockCountPerTurn\",\"type\":\"uint24\"},{\"internalType\":\"uint32\",\"name\":\"checkGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"stalenessSeconds\",\"type\":\"uint24\"},{\"internalType\":\"uint16\",\"name\":\"gasCeilingMultiplier\",\"type\":\"uint16\"},{\"internalType\":\"uint96\",\"name\":\"minUpkeepSpend\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"maxPerformGas\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"fallbackGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fallbackLinkPrice\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"transcoder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"registrar\",\"type\":\"address\"}],\"internalType\":\"structConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"keepers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"payees\",\"type\":\"address[]\"}],\"name\":\"setKeepers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"},{\"internalType\":\"enumKeeperRegistryBase1_3.MigrationPermission\",\"name\":\"permission\",\"type\":\"uint8\"}],\"name\":\"setPeerRegistryMigrationPermission\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"name\":\"setUpkeepGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"keeper\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferPayeeship\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"proposed\",\"type\":\"address\"}],\"name\":\"transferUpkeepAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"newCheckData\",\"type\":\"bytes\"}],\"name\":\"updateCheckData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"enumUpkeepFormat\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawPayment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x6101806040527f420000000000000000000000000000000000000f00000000000000000000000060e0526c6c000000000000000000000000610100523480156200004857600080fd5b50604051620048c1380380620048c18339810160408190526200006b91620008a7565b816001600160a01b0316638811cbe86040518163ffffffff1660e01b815260040160206040518083038186803b158015620000a557600080fd5b505afa158015620000ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e09190620009ce565b826001600160a01b0316635077b2106040518163ffffffff1660e01b815260040160206040518083038186803b1580156200011a57600080fd5b505afa1580156200012f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001559190620009f1565b836001600160a01b0316631b6b6d236040518163ffffffff1660e01b815260040160206040518083038186803b1580156200018f57600080fd5b505afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca919062000880565b846001600160a01b031663ad1783616040518163ffffffff1660e01b815260040160206040518083038186803b1580156200020457600080fd5b505afa15801562000219573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200023f919062000880565b856001600160a01b0316634584a4196040518163ffffffff1660e01b815260040160206040518083038186803b1580156200027957600080fd5b505afa1580156200028e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b4919062000880565b33806000816200030b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200033e576200033e816200041b565b5050600160029081556003805460ff1916905586915081111562000366576200036662000b42565b6101208160028111156200037e576200037e62000b42565b60f81b9052506101408490526001600160a01b0383161580620003a857506001600160a01b038216155b80620003bb57506001600160a01b038116155b15620003da57604051637138356f60e01b815260040160405180910390fd5b6001600160601b0319606093841b811660805291831b821660a052821b811660c0529085901b16610160525062000413905081620004c7565b505062000b71565b6001600160a01b038116331415620004765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000302565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620004d1620007bc565b600e5460e082015163ffffffff918216911610156200050357604051630e6af04160e21b815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516001600160601b031681526020018260e0015163ffffffff168152602001600d60010160049054906101000a900463ffffffff1663ffffffff16815250600d60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600f81905550806101200151601081905550806101400151601360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806101600151601460006101000a8154816001600160a01b0302191690836001600160a01b031602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de32581604051620007b1919062000a0b565b60405180910390a150565b6000546001600160a01b03163314620008185760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000302565b565b8051620008278162000b58565b919050565b805161ffff811681146200082757600080fd5b805162ffffff811681146200082757600080fd5b805163ffffffff811681146200082757600080fd5b80516001600160601b03811681146200082757600080fd5b6000602082840312156200089357600080fd5b8151620008a08162000b58565b9392505050565b6000808284036101a0811215620008bd57600080fd5b8351620008ca8162000b58565b9250610180601f198201811315620008e157600080fd5b620008eb62000b0a565b9150620008fb6020860162000853565b82526200090b6040860162000853565b60208301526200091e606086016200083f565b6040830152620009316080860162000853565b60608301526200094460a086016200083f565b60808301526200095760c086016200082c565b60a08301526200096a60e0860162000868565b60c08301526101006200097f81870162000853565b60e084015261012080870151828501526101409150818701518185015250610160620009ad8188016200081a565b82850152620009be8388016200081a565b9084015250929590945092505050565b600060208284031215620009e157600080fd5b815160038110620008a057600080fd5b60006020828403121562000a0457600080fd5b5051919050565b815163ffffffff1681526101808101602083015162000a32602084018263ffffffff169052565b50604083015162000a4a604084018262ffffff169052565b50606083015162000a63606084018263ffffffff169052565b50608083015162000a7b608084018262ffffff169052565b5060a083015162000a9260a084018261ffff169052565b5060c083015162000aae60c08401826001600160601b03169052565b5060e083015162000ac760e084018263ffffffff169052565b5061010083810151908301526101208084015190830152610140808401516001600160a01b03908116918401919091526101609384015116929091019190915290565b60405161018081016001600160401b038111828210171562000b3c57634e487b7160e01b600052604160045260246000fd5b60405290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b038116811462000b6e57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160f81c610140516101605160601c613c9662000c2b600039600081816103600152610a4c0152600081816105e601526125a7015260008181610749015281816125fa01526127760152600081816106a101526127ae0152600081816106d501526126e501526000818161059001526122db01526000818161089101526123bc01526000818161046e01526114b90152613c966000f3fe6080604052600436106103015760003560e01c80638811cbe81161018f578063b148ab6b116100e1578063c80480221161008a578063ef47a0ce11610064578063ef47a0ce146109b4578063f2fde38b146109d4578063faa3e996146109f457610310565b8063c8048022146108d3578063da5c674114610994578063eb5dcd6c1461084957610310565b8063b7fdb436116100bb578063b7fdb4361461090e578063c41b813a1461092e578063c7c3a19a1461095f57610310565b8063b148ab6b146108d3578063b657bc9c146108ee578063b79550be1461056957610310565b80639fab438611610143578063a72aa27e1161011d578063a72aa27e14610864578063ad1783611461087f578063b121e147146108b357610310565b80639fab438614610809578063a4c0ed3614610829578063a710b2211461084957610310565b80638e86139b116101745780638e86139b1461079657806393f0c1fc146107b1578063948108f7146107ee57610310565b80638811cbe8146107375780638da5cb5b1461076b57610310565b80635077b210116102535780637d9b97e0116101fc578063850cce34116101d6578063850cce34146106c357806385c1b0ba146106f75780638765ecbe1461071757610310565b80637d9b97e0146105695780637f37618e1461068f5780638456cb591461056957610310565b8063744bfe611161022d578063744bfe611461044157806379ba50971461065a5780637bbaf1ea1461066f57610310565b80635077b210146105d45780635165f2f5146106165780635c975abb1461063657610310565b80631a2af011116102b55780633f4ba83a1161028f5780633f4ba83a146105695780634584a4191461057e57806348013d7b146105b257610310565b80631a2af011146104415780631b6b6d231461045c5780631e12b8a51461049057610310565b8063181f5a77116102e6578063181f5a77146103a75780631865c57d146103fd578063187256e81461042157610310565b806306e3b632146103185780630852c7c91461034e57610310565b366103105761030e610a47565b005b61030e610a47565b34801561032457600080fd5b50610338610333366004613377565b610a72565b6040516103459190613649565b60405180910390f35b34801561035a57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610345565b3480156103b357600080fd5b506103f06040518060400160405280601481526020017f4b6565706572526567697374727920312e332e3000000000000000000000000081525081565b60405161034591906136da565b34801561040957600080fd5b50610412610b6e565b6040516103459392919061375a565b34801561042d57600080fd5b5061030e61043c366004612ff7565b610e26565b34801561044d57600080fd5b5061030e61043c366004613308565b34801561046857600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561049c57600080fd5b506105296104ab366004612fa9565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff1692810183905260019091015460ff16151592018290529192909190565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845291151560208401526bffffffffffffffffffffffff1690820152606001610345565b34801561057557600080fd5b5061030e610e32565b34801561058a57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156105be57600080fd5b506105c7600181565b604051610345919061373e565b3480156105e057600080fd5b506106087f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610345565b34801561062257600080fd5b5061030e6106313660046132d6565b610e3a565b34801561064257600080fd5b5060035460ff165b6040519015158152602001610345565b34801561066657600080fd5b5061030e610fc6565b34801561067b57600080fd5b5061064a61068a36600461332b565b6110c8565b34801561069b57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156106cf57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561070357600080fd5b5061030e610712366004613162565b611191565b34801561072357600080fd5b5061030e6107323660046132d6565b61119e565b34801561074357600080fd5b506105c77f000000000000000000000000000000000000000000000000000000000000000081565b34801561077757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610382565b3480156107a257600080fd5b5061030e61043c3660046131b6565b3480156107bd57600080fd5b506107d16107cc3660046132d6565b61134a565b6040516bffffffffffffffffffffffff9091168152602001610345565b3480156107fa57600080fd5b5061030e61043c3660046133bc565b34801561081557600080fd5b5061030e61082436600461332b565b611368565b34801561083557600080fd5b5061030e610844366004613032565b6114a1565b34801561085557600080fd5b5061030e61043c366004612fc4565b34801561087057600080fd5b5061030e61043c366004613399565b34801561088b57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156108bf57600080fd5b5061030e6108ce366004612fa9565b611698565b3480156108df57600080fd5b5061030e6108ce3660046132d6565b3480156108fa57600080fd5b506107d16109093660046132d6565b6116a3565b34801561091a57600080fd5b5061030e610929366004613102565b6116c4565b34801561093a57600080fd5b5061094e610949366004613308565b6116d2565b6040516103459594939291906136ed565b34801561096b57600080fd5b5061097f61097a3660046132d6565b6116f4565b604051610345999897969594939291906135b7565b3480156109a057600080fd5b506106086109af36600461308c565b6118c4565b3480156109c057600080fd5b5061030e6109cf3660046131f8565b6118d7565b3480156109e057600080fd5b5061030e6109ef366004612fa9565b611c23565b348015610a0057600080fd5b50610a3a610a0f366004612fa9565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602052604090205460ff1690565b6040516103459190613724565b610a707f0000000000000000000000000000000000000000000000000000000000000000611c34565b565b60606000610a806005611c58565b9050808410610abb576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610acd57610aca8482613939565b92505b60008367ffffffffffffffff811115610ae857610ae8613af2565b604051908082528060200260200182016040528015610b11578160200160208202803683370190505b50905060005b84811015610b6357610b34610b2c8288613879565b600590611c62565b828281518110610b4657610b46613ac3565b602090810291909101015280610b5b816139fd565b915050610b17565b509150505b92915050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526040805161012081018252600d5463ffffffff8082168352640100000000808304821660208086019190915262ffffff6801000000000000000085048116868801526b010000000000000000000000850484166060878101919091526f010000000000000000000000000000008604909116608087015261ffff720100000000000000000000000000000000000086041660a08701526bffffffffffffffffffffffff74010000000000000000000000000000000000000000909504851660c0870152600e5480851660e088015292909204909216610100850181905287526011549092169086015260125492850192909252610cf06005611c58565b606080860191909152815163ffffffff908116855260208084015182168187015260408085015162ffffff90811682890152858501518416948801949094526080808601519094169387019390935260a08085015161ffff169087015260c0808501516bffffffffffffffffffffffff169087015260e08085015190921691860191909152600f5461010086015260105461012086015260135473ffffffffffffffffffffffffffffffffffffffff90811661014087015260145416610160860152600480548351818402810184019094528084528793879390918391830182828015610e1357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610de8575b5050505050905093509350935050909192565b610e2e610a47565b5050565b610a70610a47565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e0820152610f1981611c75565b8060e00151610f54576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902060020180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055610f96600583611d22565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461104c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006110d660035460ff1690565b1561113d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611043565b611189611184338686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250611d2e915050565b611e18565b949350505050565b611199610a47565b505050565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e082015261127d81611c75565b8060e00151156112b9576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902060020180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000017905561131a60058361229c565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b60008060006113576122a8565b9150915061118984838360006124a3565b60008381526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e082015261144781611c75565b6000848152600b60205260409020611460908484612dcc565b50837f7b778136e5211932b51a145badd01959415e79e051a933604b3d323f862dcabf848460405161149392919061368d565b60405180910390a250505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611510576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461154a576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611558828401846132d6565b600081815260076020526040902060020154909150640100000000900463ffffffff908116146115b4576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020546115dc9085906bffffffffffffffffffffffff16613891565b600082815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff92909216919091179055601254611633908590613879565b6012556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b6116a0610a47565b50565b600081815260076020526040812060020154610b689063ffffffff1661134a565b6116cc610a47565b50505050565b60606000806000806116e2612914565b6116ea610a47565b9295509295909350565b600081815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff9081168488019081526001860154928316858801908152939092048116606080860191825260029096015463ffffffff80821660808801819052640100000000830490911660a0880190815268010000000000000000830490941660c088018190527c010000000000000000000000000000000000000000000000000000000090920460ff16151560e088019081528c8c52600b909a52978a2086519451925193519551995181548c9b999a8c9a8b9a8b9a8b9a8b9a8b9a939998959795969195939490939091879061181b906139a9565b80601f0160208091040260200160405190810160405280929190818152602001828054611847906139a9565b80156118945780601f1061186957610100808354040283529160200191611894565b820191906000526020600020905b81548152906001019060200180831161187757829003601f168201915b505050505096508263ffffffff169250995099509950995099509950995099509950509193959799909294969850565b60006118ce610a47565b95945050505050565b6118df61294c565b600e5460e082015163ffffffff91821691161015611929576040517f39abc10400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516bffffffffffffffffffffffff1681526020018260e0015163ffffffff168152602001600d60010160049054906101000a900463ffffffff1663ffffffff16815250600d60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600f81905550806101200151601081905550806101400151601360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806101600151601460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de32581604051611c18919061374b565b60405180910390a150565b611c2b61294c565b6116a0816129cd565b3660008037600080366000845af43d6000803e808015611c53573d6000f35b3d6000fd5b6000610b68825490565b6000611c6e8383612ac3565b9392505050565b806060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611cde576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015163ffffffff908116146116a0576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c6e8383612aed565b611d846040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206002015463ffffffff169080611da66122a8565b915091506000611db8848484896124a3565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff909b168b5260208b0199909952978901969096526bffffffffffffffffffffffff9096166060880152608087019190915260a086015250505060c082015290565b6000600280541415611e86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611043565b600280805560208084015160009081526007825260409081902081516101008101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811696840196909652600184015490811694830194909452909204831660608301529092015463ffffffff808216608085015264010000000082041660a0840181905268010000000000000000820490921660c084015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e08301524310611f9e576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611fb18184600001518560600151612b3c565b60005a90506000634585e33b60e01b8560400151604051602401611fd591906136da565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905061204785608001518460c0015183612c8d565b93505a6120549083613939565b9150600061206d838760a001518860c0015160016124a3565b60208088015160009081526007909152604090205490915061209e9082906bffffffffffffffffffffffff16613950565b6020878101805160009081526007909252604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9586161790559051825290206001015461210191839116613891565b60208781018051600090815260078352604080822060010180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9687161790558a5192518252808220805486166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff958616021790558a51909216815260089092529020546121ba91839174010000000000000000000000000000000000000000900416613891565b60086000886000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550856000015173ffffffffffffffffffffffffffffffffffffffff1685151587602001517fcaacad83e47cc45c280d487ec84184eee2fa3b54ebaa393bda7549f13da228f6848a60400151604051612286929190613801565b60405180910390a4505050506001600255919050565b6000611c6e8383612cd9565b6000806000600d600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561233f57600080fd5b505afa158015612353573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237791906133df565b50945090925084915050801561239b57506123928242613939565b8463ffffffff16105b806123a7575060008113155b156123b657600f5495506123ba565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245891906133df565b50945090925084915050801561247c57506124738242613939565b8463ffffffff16105b80612488575060008113155b1561249757601054945061249b565b8094505b505050509091565b6040805161012081018252600d5463ffffffff80821683526401000000008083048216602085015268010000000000000000830462ffffff908116958501959095526b0100000000000000000000008304821660608501526f01000000000000000000000000000000830490941660808401527201000000000000000000000000000000000000820461ffff1660a08401819052740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1660c0840152600e5480821660e085015293909304909216610100820152600091829061258a90876138fc565b90508380156125985750803a105b156125a057503a5b60006125cc7f000000000000000000000000000000000000000000000000000000000000000089613879565b6125d690836138fc565b83519091506000906125f29063ffffffff16633b9aca00613879565b9050600060027f0000000000000000000000000000000000000000000000000000000000000000600281111561262a5761262a613a65565b141561277257604080516000815260208101909152871561268957600036604051806080016040528060488152602001613b326048913960405160200161267393929190613590565b60405160208183030381529060405290506126a8565b6040518061014001604052806101108152602001613b7a610110913990505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906349948e0e9061271a9084906004016136da565b60206040518083038186803b15801561273257600080fd5b505afa158015612746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276a91906132ef565b91505061284d565b60017f000000000000000000000000000000000000000000000000000000000000000060028111156127a6576127a6613a65565b141561284d577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561281257600080fd5b505afa158015612826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284a91906132ef565b90505b8661286957808560a0015161ffff1661286691906138fc565b90505b6000856020015163ffffffff1664e8d4a5100061288691906138fc565b89846128928588613879565b6128a090633b9aca006138fc565b6128aa91906138fc565b6128b491906138c1565b6128be9190613879565b90506b033b2e3c9fd0803ce8000000811115612906576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b3215610a70576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314610a70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401611043565b73ffffffffffffffffffffffffffffffffffffffff8116331415612a4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401611043565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110612ada57612ada613ac3565b9060005260206000200154905092915050565b6000818152600183016020526040812054612b3457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b68565b506000610b68565b8260e0015115612b78576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff16612bda576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff16811115612c23576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff161415611199576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a611388811015612c9f57600080fd5b611388810390508460408204820311612cb757600080fd5b50823b612cc357600080fd5b60008083516020850160008789f1949350505050565b60008181526001830160205260408120548015612dc2576000612cfd600183613939565b8554909150600090612d1190600190613939565b9050818114612d76576000866000018281548110612d3157612d31613ac3565b9060005260206000200154905080876000018481548110612d5457612d54613ac3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612d8757612d87613a94565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b68565b6000915050610b68565b828054612dd8906139a9565b90600052602060002090601f016020900481019282612dfa5760008555612e5e565b82601f10612e31578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555612e5e565b82800160010185558215612e5e579182015b82811115612e5e578235825591602001919060010190612e43565b50612e6a929150612e6e565b5090565b5b80821115612e6a5760008155600101612e6f565b803573ffffffffffffffffffffffffffffffffffffffff81168114612ea757600080fd5b919050565b60008083601f840112612ebe57600080fd5b50813567ffffffffffffffff811115612ed657600080fd5b6020830191508360208260051b8501011115612ef157600080fd5b9250929050565b60008083601f840112612f0a57600080fd5b50813567ffffffffffffffff811115612f2257600080fd5b602083019150836020828501011115612ef157600080fd5b803561ffff81168114612ea757600080fd5b803562ffffff81168114612ea757600080fd5b803563ffffffff81168114612ea757600080fd5b805169ffffffffffffffffffff81168114612ea757600080fd5b80356bffffffffffffffffffffffff81168114612ea757600080fd5b600060208284031215612fbb57600080fd5b611c6e82612e83565b60008060408385031215612fd757600080fd5b612fe083612e83565b9150612fee60208401612e83565b90509250929050565b6000806040838503121561300a57600080fd5b61301383612e83565b915060208301356004811061302757600080fd5b809150509250929050565b6000806000806060858703121561304857600080fd5b61305185612e83565b935060208501359250604085013567ffffffffffffffff81111561307457600080fd5b61308087828801612ef8565b95989497509550505050565b6000806000806000608086880312156130a457600080fd5b6130ad86612e83565b94506130bb60208701612f5f565b93506130c960408701612e83565b9250606086013567ffffffffffffffff8111156130e557600080fd5b6130f188828901612ef8565b969995985093965092949392505050565b6000806000806040858703121561311857600080fd5b843567ffffffffffffffff8082111561313057600080fd5b61313c88838901612eac565b9096509450602087013591508082111561315557600080fd5b5061308087828801612eac565b60008060006040848603121561317757600080fd5b833567ffffffffffffffff81111561318e57600080fd5b61319a86828701612eac565b90945092506131ad905060208501612e83565b90509250925092565b600080602083850312156131c957600080fd5b823567ffffffffffffffff8111156131e057600080fd5b6131ec85828601612ef8565b90969095509350505050565b6000610180828403121561320b57600080fd5b613213613828565b61321c83612f5f565b815261322a60208401612f5f565b602082015261323b60408401612f4c565b604082015261324c60608401612f5f565b606082015261325d60808401612f4c565b608082015261326e60a08401612f3a565b60a082015261327f60c08401612f8d565b60c082015261329060e08401612f5f565b60e0820152610100838101359082015261012080840135908201526101406132b9818501612e83565b908201526101606132cb848201612e83565b908201529392505050565b6000602082840312156132e857600080fd5b5035919050565b60006020828403121561330157600080fd5b5051919050565b6000806040838503121561331b57600080fd5b82359150612fee60208401612e83565b60008060006040848603121561334057600080fd5b83359250602084013567ffffffffffffffff81111561335e57600080fd5b61336a86828701612ef8565b9497909650939450505050565b6000806040838503121561338a57600080fd5b50508035926020909101359150565b600080604083850312156133ac57600080fd5b82359150612fee60208401612f5f565b600080604083850312156133cf57600080fd5b82359150612fee60208401612f8d565b600080600080600060a086880312156133f757600080fd5b61340086612f73565b945060208601519350604086015192506060860151915061342360808701612f73565b90509295509295909350565b6000815180845261344781602086016020860161397d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805163ffffffff168252602081015161349a602084018263ffffffff169052565b5060408101516134b1604084018262ffffff169052565b5060608101516134c9606084018263ffffffff169052565b5060808101516134e0608084018262ffffff169052565b5060a08101516134f660a084018261ffff169052565b5060c081015161351660c08401826bffffffffffffffffffffffff169052565b5060e081015161352e60e084018263ffffffff169052565b50610100818101519083015261012080820151908301526101408082015173ffffffffffffffffffffffffffffffffffffffff81168285015250506101608181015173ffffffffffffffffffffffffffffffffffffffff8116848301526116cc565b8284823760008382016000815283516135ad81836020880161397d565b0195945050505050565b600061012073ffffffffffffffffffffffffffffffffffffffff808d16845263ffffffff8c1660208501528160408501526135f48285018c61342f565b6bffffffffffffffffffffffff9a8b16606086015298811660808501529690961660a08301525067ffffffffffffffff9390931660c0840152941660e082015292151561010090930192909252949350505050565b6020808252825182820181905260009190848201906040850190845b8181101561368157835183529284019291840191600101613665565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b602081526000611c6e602083018461342f565b60a08152600061370060a083018861342f565b90508560208301528460408301528360608301528260808301529695505050505050565b602081016004831061373857613738613a65565b91905290565b6020810161373883613b21565b6101808101610b688284613479565b600061022080830163ffffffff875116845260206bffffffffffffffffffffffff81890151168186015260408801516040860152606088015160608601526137a56080860188613479565b6102008501929092528451908190526102408401918086019160005b818110156137f357835173ffffffffffffffffffffffffffffffffffffffff16855293820193928201926001016137c1565b509298975050505050505050565b6bffffffffffffffffffffffff83168152604060208201526000611189604083018461342f565b604051610180810167ffffffffffffffff81118282101715613873577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b6000821982111561388c5761388c613a36565b500190565b60006bffffffffffffffffffffffff8083168185168083038211156138b8576138b8613a36565b01949350505050565b6000826138f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561393457613934613a36565b500290565b60008282101561394b5761394b613a36565b500390565b60006bffffffffffffffffffffffff8381169083168181101561397557613975613a36565b039392505050565b60005b83811015613998578181015183820152602001613980565b838111156116cc5750506000910152565b600181811c908216806139bd57607f821691505b602082108114156139f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613a2f57613a2f613a36565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600381106116a0576116a0613a6556fe3078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666663078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + Bin: "0x6101806040527f420000000000000000000000000000000000000f00000000000000000000000060e0526c6c000000000000000000000000610100523480156200004857600080fd5b50604051620048cd380380620048cd8339810160408190526200006b91620008a7565b816001600160a01b0316638811cbe86040518163ffffffff1660e01b815260040160206040518083038186803b158015620000a557600080fd5b505afa158015620000ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e09190620009ce565b826001600160a01b0316635077b2106040518163ffffffff1660e01b815260040160206040518083038186803b1580156200011a57600080fd5b505afa1580156200012f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001559190620009f1565b836001600160a01b0316631b6b6d236040518163ffffffff1660e01b815260040160206040518083038186803b1580156200018f57600080fd5b505afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca919062000880565b846001600160a01b031663ad1783616040518163ffffffff1660e01b815260040160206040518083038186803b1580156200020457600080fd5b505afa15801562000219573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200023f919062000880565b856001600160a01b0316634584a4196040518163ffffffff1660e01b815260040160206040518083038186803b1580156200027957600080fd5b505afa1580156200028e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b4919062000880565b33806000816200030b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200033e576200033e816200041b565b5050600160029081556003805460ff1916905586915081111562000366576200036662000b42565b6101208160028111156200037e576200037e62000b42565b60f81b9052506101408490526001600160a01b0383161580620003a857506001600160a01b038216155b80620003bb57506001600160a01b038116155b15620003da57604051637138356f60e01b815260040160405180910390fd5b6001600160601b0319606093841b811660805291831b821660a052821b811660c0529085901b16610160525062000413905081620004c7565b505062000b71565b6001600160a01b038116331415620004765760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000302565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620004d1620007bc565b600e5460e082015163ffffffff918216911610156200050357604051630e6af04160e21b815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516001600160601b031681526020018260e0015163ffffffff168152602001600d60010160049054906101000a900463ffffffff1663ffffffff16815250600d60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600f81905550806101200151601081905550806101400151601360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806101600151601460006101000a8154816001600160a01b0302191690836001600160a01b031602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de32581604051620007b1919062000a0b565b60405180910390a150565b6000546001600160a01b03163314620008185760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000302565b565b8051620008278162000b58565b919050565b805161ffff811681146200082757600080fd5b805162ffffff811681146200082757600080fd5b805163ffffffff811681146200082757600080fd5b80516001600160601b03811681146200082757600080fd5b6000602082840312156200089357600080fd5b8151620008a08162000b58565b9392505050565b6000808284036101a0811215620008bd57600080fd5b8351620008ca8162000b58565b9250610180601f198201811315620008e157600080fd5b620008eb62000b0a565b9150620008fb6020860162000853565b82526200090b6040860162000853565b60208301526200091e606086016200083f565b6040830152620009316080860162000853565b60608301526200094460a086016200083f565b60808301526200095760c086016200082c565b60a08301526200096a60e0860162000868565b60c08301526101006200097f81870162000853565b60e084015261012080870151828501526101409150818701518185015250610160620009ad8188016200081a565b82850152620009be8388016200081a565b9084015250929590945092505050565b600060208284031215620009e157600080fd5b815160038110620008a057600080fd5b60006020828403121562000a0457600080fd5b5051919050565b815163ffffffff1681526101808101602083015162000a32602084018263ffffffff169052565b50604083015162000a4a604084018262ffffff169052565b50606083015162000a63606084018263ffffffff169052565b50608083015162000a7b608084018262ffffff169052565b5060a083015162000a9260a084018261ffff169052565b5060c083015162000aae60c08401826001600160601b03169052565b5060e083015162000ac760e084018263ffffffff169052565b5061010083810151908301526101208084015190830152610140808401516001600160a01b03908116918401919091526101609384015116929091019190915290565b60405161018081016001600160401b038111828210171562000b3c57634e487b7160e01b600052604160045260246000fd5b60405290565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b038116811462000b6e57600080fd5b50565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160f81c610140516101605160601c613ca262000c2b600039600081816103600152610a4c0152600081816105e601526125460152600081816107490152818161259901526127150152600081816106a1015261274d0152600081816106d50152612684015260008181610590015261227a015260008181610891015261235b01526000818161046e015261144e0152613ca26000f3fe6080604052600436106103015760003560e01c80638811cbe81161018f578063b148ab6b116100e1578063c80480221161008a578063ef47a0ce11610064578063ef47a0ce146109b4578063f2fde38b146109d4578063faa3e996146109f457610310565b8063c8048022146108d3578063da5c674114610994578063eb5dcd6c1461084957610310565b8063b7fdb436116100bb578063b7fdb4361461090e578063c41b813a1461092e578063c7c3a19a1461095f57610310565b8063b148ab6b146108d3578063b657bc9c146108ee578063b79550be1461056957610310565b80639fab438611610143578063a72aa27e1161011d578063a72aa27e14610864578063ad1783611461087f578063b121e147146108b357610310565b80639fab438614610809578063a4c0ed3614610829578063a710b2211461084957610310565b80638e86139b116101745780638e86139b1461079657806393f0c1fc146107b1578063948108f7146107ee57610310565b80638811cbe8146107375780638da5cb5b1461076b57610310565b80635077b210116102535780637d9b97e0116101fc578063850cce34116101d6578063850cce34146106c357806385c1b0ba146106f75780638765ecbe1461071757610310565b80637d9b97e0146105695780637f37618e1461068f5780638456cb591461056957610310565b8063744bfe611161022d578063744bfe611461044157806379ba50971461065a5780637bbaf1ea1461066f57610310565b80635077b210146105d45780635165f2f5146106165780635c975abb1461063657610310565b80631a2af011116102b55780633f4ba83a1161028f5780633f4ba83a146105695780634584a4191461057e57806348013d7b146105b257610310565b80631a2af011146104415780631b6b6d231461045c5780631e12b8a51461049057610310565b8063181f5a77116102e6578063181f5a77146103a75780631865c57d146103fd578063187256e81461042157610310565b806306e3b632146103185780630852c7c91461034e57610310565b366103105761030e610a47565b005b61030e610a47565b34801561032457600080fd5b50610338610333366004613383565b610a72565b6040516103459190613655565b60405180910390f35b34801561035a57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610345565b3480156103b357600080fd5b506103f06040518060400160405280601481526020017f4b6565706572526567697374727920312e332e3000000000000000000000000081525081565b60405161034591906136e6565b34801561040957600080fd5b50610412610b6e565b60405161034593929190613766565b34801561042d57600080fd5b5061030e61043c366004613003565b610e26565b34801561044d57600080fd5b5061030e61043c366004613314565b34801561046857600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561049c57600080fd5b506105296104ab366004612fb5565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526008602090815260409182902082516060810184528154948516808252740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff1692810183905260019091015460ff16151592018290529192909190565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845291151560208401526bffffffffffffffffffffffff1690820152606001610345565b34801561057557600080fd5b5061030e610e32565b34801561058a57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156105be57600080fd5b506105c7600181565b604051610345919061374a565b3480156105e057600080fd5b506106087f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610345565b34801561062257600080fd5b5061030e6106313660046132e2565b610e3a565b34801561064257600080fd5b5060035460ff165b6040519015158152602001610345565b34801561066657600080fd5b5061030e610fc6565b34801561067b57600080fd5b5061064a61068a366004613337565b6110c8565b34801561069b57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156106cf57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561070357600080fd5b5061030e61071236600461316e565b611126565b34801561072357600080fd5b5061030e6107323660046132e2565b611133565b34801561074357600080fd5b506105c77f000000000000000000000000000000000000000000000000000000000000000081565b34801561077757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610382565b3480156107a257600080fd5b5061030e61043c3660046131c2565b3480156107bd57600080fd5b506107d16107cc3660046132e2565b6112df565b6040516bffffffffffffffffffffffff9091168152602001610345565b3480156107fa57600080fd5b5061030e61043c3660046133c8565b34801561081557600080fd5b5061030e610824366004613337565b6112fd565b34801561083557600080fd5b5061030e61084436600461303e565b611436565b34801561085557600080fd5b5061030e61043c366004612fd0565b34801561087057600080fd5b5061030e61043c3660046133a5565b34801561088b57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156108bf57600080fd5b5061030e6108ce366004612fb5565b61162d565b3480156108df57600080fd5b5061030e6108ce3660046132e2565b3480156108fa57600080fd5b506107d16109093660046132e2565b611638565b34801561091a57600080fd5b5061030e61092936600461310e565b611659565b34801561093a57600080fd5b5061094e610949366004613314565b611667565b6040516103459594939291906136f9565b34801561096b57600080fd5b5061097f61097a3660046132e2565b611689565b604051610345999897969594939291906135c3565b3480156109a057600080fd5b506106086109af366004613098565b611859565b3480156109c057600080fd5b5061030e6109cf366004613204565b61186c565b3480156109e057600080fd5b5061030e6109ef366004612fb5565b611bb8565b348015610a0057600080fd5b50610a3a610a0f366004612fb5565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602052604090205460ff1690565b6040516103459190613730565b610a707f0000000000000000000000000000000000000000000000000000000000000000611bc9565b565b60606000610a806005611bed565b9050808410610abb576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610acd57610aca8482613945565b92505b60008367ffffffffffffffff811115610ae857610ae8613afe565b604051908082528060200260200182016040528015610b11578160200160208202803683370190505b50905060005b84811015610b6357610b34610b2c8288613885565b600590611bf7565b828281518110610b4657610b46613acf565b602090810291909101015280610b5b81613a09565b915050610b17565b509150505b92915050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101919091526040805161012081018252600d5463ffffffff8082168352640100000000808304821660208086019190915262ffffff6801000000000000000085048116868801526b010000000000000000000000850484166060878101919091526f010000000000000000000000000000008604909116608087015261ffff720100000000000000000000000000000000000086041660a08701526bffffffffffffffffffffffff74010000000000000000000000000000000000000000909504851660c0870152600e5480851660e088015292909204909216610100850181905287526011549092169086015260125492850192909252610cf06005611bed565b606080860191909152815163ffffffff908116855260208084015182168187015260408085015162ffffff90811682890152858501518416948801949094526080808601519094169387019390935260a08085015161ffff169087015260c0808501516bffffffffffffffffffffffff169087015260e08085015190921691860191909152600f5461010086015260105461012086015260135473ffffffffffffffffffffffffffffffffffffffff90811661014087015260145416610160860152600480548351818402810184019094528084528793879390918391830182828015610e1357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610de8575b5050505050905093509350935050909192565b610e2e610a47565b5050565b610a70610a47565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e0820152610f1981611c0a565b8060e00151610f54576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902060020180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff169055610f96600583611cb7565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461104c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006110d2611cc3565b61111e611119338686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250611d30915050565b611e1a565b949350505050565b61112e610a47565b505050565b60008181526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e082015261121281611c0a565b8060e001511561124e576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260076020526040902060020180547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c01000000000000000000000000000000000000000000000000000000001790556112af60058361223b565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b60008060006112ec612247565b9150915061111e8483836000612442565b60008381526007602090815260409182902082516101008101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811695840195909552600184015490811695830195909552909304821660608401526002015463ffffffff808216608085015264010000000082041660a084015268010000000000000000810490911660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e08201526113dc81611c0a565b6000848152600b602052604090206113f5908484612ddd565b50837f7b778136e5211932b51a145badd01959415e79e051a933604b3d323f862dcabf8484604051611428929190613699565b60405180910390a250505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146114a5576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146114df576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006114ed828401846132e2565b600081815260076020526040902060020154909150640100000000900463ffffffff90811614611549576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020546115719085906bffffffffffffffffffffffff1661389d565b600082815260076020526040902080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790556012546115c8908590613885565b6012556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b611635610a47565b50565b600081815260076020526040812060020154610b689063ffffffff166112df565b611661610a47565b50505050565b60606000806000806116776128b3565b61167f610a47565b9295509295909350565b600081815260076020908152604080832081516101008101835281546bffffffffffffffffffffffff80821683526c010000000000000000000000009182900473ffffffffffffffffffffffffffffffffffffffff9081168488019081526001860154928316858801908152939092048116606080860191825260029096015463ffffffff80821660808801819052640100000000830490911660a0880190815268010000000000000000830490941660c088018190527c010000000000000000000000000000000000000000000000000000000090920460ff16151560e088019081528c8c52600b909a52978a2086519451925193519551995181548c9b999a8c9a8b9a8b9a8b9a8b9a8b9a93999895979596919593949093909187906117b0906139b5565b80601f01602080910402602001604051908101604052809291908181526020018280546117dc906139b5565b80156118295780601f106117fe57610100808354040283529160200191611829565b820191906000526020600020905b81548152906001019060200180831161180c57829003601f168201915b505050505096508263ffffffff169250995099509950995099509950995099509950509193959799909294969850565b6000611863610a47565b95945050505050565b6118746128eb565b600e5460e082015163ffffffff918216911610156118be576040517f39abc10400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101200160405280826000015163ffffffff168152602001826020015163ffffffff168152602001826040015162ffffff168152602001826060015163ffffffff168152602001826080015162ffffff1681526020018260a0015161ffff1681526020018260c001516bffffffffffffffffffffffff1681526020018260e0015163ffffffff168152602001600d60010160049054906101000a900463ffffffff1663ffffffff16815250600d60008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160086101000a81548162ffffff021916908362ffffff160217905550606082015181600001600b6101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600f6101000a81548162ffffff021916908362ffffff16021790555060a08201518160000160126101000a81548161ffff021916908361ffff16021790555060c08201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060e08201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff160217905550905050806101000151600f81905550806101200151601081905550806101400151601360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806101600151601460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507ffe125a41957477226ba20f85ef30a4024ea3bb8d066521ddc16df3f2944de32581604051611bad9190613757565b60405180910390a150565b611bc06128eb565b6116358161296c565b3660008037600080366000845af43d6000803e808015611be8573d6000f35b3d6000fd5b6000610b68825490565b6000611c038383612a62565b9392505050565b806060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611c73576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a081015163ffffffff90811614611635576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c038383612a8c565b60035460ff1615610a70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611043565b611d866040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600081526020016000815260200160008152602001600081525090565b60008481526007602052604081206002015463ffffffff169080611da8612247565b915091506000611dba84848489612442565b6040805160e08101825273ffffffffffffffffffffffffffffffffffffffff909b168b5260208b0199909952978901969096526bffffffffffffffffffffffff9096166060880152608087019190915260a086015250505060c082015290565b6000611e24612adb565b60208083015160009081526007825260409081902081516101008101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811696840196909652600184015490811694830194909452909204831660608301526002015463ffffffff808216608084015264010000000082041660a0830181905268010000000000000000820490931660c083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560e0820152904310611f38576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f4b8184600001518560600151612b4d565b60005a90506000634585e33b60e01b8560400151604051602401611f6f91906136e6565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050611fe185608001518460c0015183612c9e565b93505a611fee9083613945565b91506000612007838760a001518860c001516001612442565b6020808801516000908152600790915260409020549091506120389082906bffffffffffffffffffffffff1661395c565b6020878101805160009081526007909252604080832080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9586161790559051825290206001015461209b9183911661389d565b60208781018051600090815260078352604080822060010180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9687161790558a5192518252808220805486166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff958616021790558a51909216815260089092529020546121549183917401000000000000000000000000000000000000000090041661389d565b60086000886000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550856000015173ffffffffffffffffffffffffffffffffffffffff1685151587602001517fcaacad83e47cc45c280d487ec84184eee2fa3b54ebaa393bda7549f13da228f6848a6040015160405161222092919061380d565b60405180910390a4505050506122366001600255565b919050565b6000611c038383612cea565b6000806000600d600001600f9054906101000a900462ffffff1662ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156122de57600080fd5b505afa1580156122f2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231691906133eb565b50945090925084915050801561233a57506123318242613945565b8463ffffffff16105b80612346575060008113155b1561235557600f549550612359565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b1580156123bf57600080fd5b505afa1580156123d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f791906133eb565b50945090925084915050801561241b57506124128242613945565b8463ffffffff16105b80612427575060008113155b1561243657601054945061243a565b8094505b505050509091565b6040805161012081018252600d5463ffffffff80821683526401000000008083048216602085015268010000000000000000830462ffffff908116958501959095526b0100000000000000000000008304821660608501526f01000000000000000000000000000000830490941660808401527201000000000000000000000000000000000000820461ffff1660a08401819052740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1660c0840152600e5480821660e08501529390930490921661010082015260009182906125299087613908565b90508380156125375750803a105b1561253f57503a5b600061256b7f000000000000000000000000000000000000000000000000000000000000000089613885565b6125759083613908565b83519091506000906125919063ffffffff16633b9aca00613885565b9050600060027f000000000000000000000000000000000000000000000000000000000000000060028111156125c9576125c9613a71565b141561271157604080516000815260208101909152871561262857600036604051806080016040528060488152602001613b3e604891396040516020016126129392919061359c565b6040516020818303038152906040529050612647565b6040518061014001604052806101108152602001613b86610110913990505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906349948e0e906126b99084906004016136e6565b60206040518083038186803b1580156126d157600080fd5b505afa1580156126e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270991906132fb565b9150506127ec565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111561274557612745613a71565b14156127ec577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156127b157600080fd5b505afa1580156127c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e991906132fb565b90505b8661280857808560a0015161ffff166128059190613908565b90505b6000856020015163ffffffff1664e8d4a510006128259190613908565b89846128318588613885565b61283f90633b9aca00613908565b6128499190613908565b61285391906138cd565b61285d9190613885565b90506b033b2e3c9fd0803ce80000008111156128a5576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b3215610a70576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314610a70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401611043565b73ffffffffffffffffffffffffffffffffffffffff81163314156129ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401611043565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110612a7957612a79613acf565b9060005260206000200154905092915050565b6000818152600183016020526040812054612ad357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b68565b506000610b68565b600280541415612b47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611043565b60028055565b8260e0015115612b89576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090206001015460ff16612beb576040517fcfbacfd800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516bffffffffffffffffffffffff16811115612c34576040517f356680b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16836020015173ffffffffffffffffffffffffffffffffffffffff16141561112e576040517f06bc104000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a611388811015612cb057600080fd5b611388810390508460408204820311612cc857600080fd5b50823b612cd457600080fd5b60008083516020850160008789f1949350505050565b60008181526001830160205260408120548015612dd3576000612d0e600183613945565b8554909150600090612d2290600190613945565b9050818114612d87576000866000018281548110612d4257612d42613acf565b9060005260206000200154905080876000018481548110612d6557612d65613acf565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612d9857612d98613aa0565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b68565b6000915050610b68565b828054612de9906139b5565b90600052602060002090601f016020900481019282612e0b5760008555612e6f565b82601f10612e42578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555612e6f565b82800160010185558215612e6f579182015b82811115612e6f578235825591602001919060010190612e54565b50612e7b929150612e7f565b5090565b5b80821115612e7b5760008155600101612e80565b803573ffffffffffffffffffffffffffffffffffffffff8116811461223657600080fd5b60008083601f840112612eca57600080fd5b50813567ffffffffffffffff811115612ee257600080fd5b6020830191508360208260051b8501011115612efd57600080fd5b9250929050565b60008083601f840112612f1657600080fd5b50813567ffffffffffffffff811115612f2e57600080fd5b602083019150836020828501011115612efd57600080fd5b803561ffff8116811461223657600080fd5b803562ffffff8116811461223657600080fd5b803563ffffffff8116811461223657600080fd5b805169ffffffffffffffffffff8116811461223657600080fd5b80356bffffffffffffffffffffffff8116811461223657600080fd5b600060208284031215612fc757600080fd5b611c0382612e94565b60008060408385031215612fe357600080fd5b612fec83612e94565b9150612ffa60208401612e94565b90509250929050565b6000806040838503121561301657600080fd5b61301f83612e94565b915060208301356004811061303357600080fd5b809150509250929050565b6000806000806060858703121561305457600080fd5b61305d85612e94565b935060208501359250604085013567ffffffffffffffff81111561308057600080fd5b61308c87828801612f04565b95989497509550505050565b6000806000806000608086880312156130b057600080fd5b6130b986612e94565b94506130c760208701612f6b565b93506130d560408701612e94565b9250606086013567ffffffffffffffff8111156130f157600080fd5b6130fd88828901612f04565b969995985093965092949392505050565b6000806000806040858703121561312457600080fd5b843567ffffffffffffffff8082111561313c57600080fd5b61314888838901612eb8565b9096509450602087013591508082111561316157600080fd5b5061308c87828801612eb8565b60008060006040848603121561318357600080fd5b833567ffffffffffffffff81111561319a57600080fd5b6131a686828701612eb8565b90945092506131b9905060208501612e94565b90509250925092565b600080602083850312156131d557600080fd5b823567ffffffffffffffff8111156131ec57600080fd5b6131f885828601612f04565b90969095509350505050565b6000610180828403121561321757600080fd5b61321f613834565b61322883612f6b565b815261323660208401612f6b565b602082015261324760408401612f58565b604082015261325860608401612f6b565b606082015261326960808401612f58565b608082015261327a60a08401612f46565b60a082015261328b60c08401612f99565b60c082015261329c60e08401612f6b565b60e0820152610100838101359082015261012080840135908201526101406132c5818501612e94565b908201526101606132d7848201612e94565b908201529392505050565b6000602082840312156132f457600080fd5b5035919050565b60006020828403121561330d57600080fd5b5051919050565b6000806040838503121561332757600080fd5b82359150612ffa60208401612e94565b60008060006040848603121561334c57600080fd5b83359250602084013567ffffffffffffffff81111561336a57600080fd5b61337686828701612f04565b9497909650939450505050565b6000806040838503121561339657600080fd5b50508035926020909101359150565b600080604083850312156133b857600080fd5b82359150612ffa60208401612f6b565b600080604083850312156133db57600080fd5b82359150612ffa60208401612f99565b600080600080600060a0868803121561340357600080fd5b61340c86612f7f565b945060208601519350604086015192506060860151915061342f60808701612f7f565b90509295509295909350565b60008151808452613453816020860160208601613989565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805163ffffffff16825260208101516134a6602084018263ffffffff169052565b5060408101516134bd604084018262ffffff169052565b5060608101516134d5606084018263ffffffff169052565b5060808101516134ec608084018262ffffff169052565b5060a081015161350260a084018261ffff169052565b5060c081015161352260c08401826bffffffffffffffffffffffff169052565b5060e081015161353a60e084018263ffffffff169052565b50610100818101519083015261012080820151908301526101408082015173ffffffffffffffffffffffffffffffffffffffff81168285015250506101608181015173ffffffffffffffffffffffffffffffffffffffff811684830152611661565b8284823760008382016000815283516135b9818360208801613989565b0195945050505050565b600061012073ffffffffffffffffffffffffffffffffffffffff808d16845263ffffffff8c1660208501528160408501526136008285018c61343b565b6bffffffffffffffffffffffff9a8b16606086015298811660808501529690961660a08301525067ffffffffffffffff9390931660c0840152941660e082015292151561010090930192909252949350505050565b6020808252825182820181905260009190848201906040850190845b8181101561368d57835183529284019291840191600101613671565b50909695505050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b602081526000611c03602083018461343b565b60a08152600061370c60a083018861343b565b90508560208301528460408301528360608301528260808301529695505050505050565b602081016004831061374457613744613a71565b91905290565b6020810161374483613b2d565b6101808101610b688284613485565b600061022080830163ffffffff875116845260206bffffffffffffffffffffffff81890151168186015260408801516040860152606088015160608601526137b16080860188613485565b6102008501929092528451908190526102408401918086019160005b818110156137ff57835173ffffffffffffffffffffffffffffffffffffffff16855293820193928201926001016137cd565b509298975050505050505050565b6bffffffffffffffffffffffff8316815260406020820152600061111e604083018461343b565b604051610180810167ffffffffffffffff8111828210171561387f577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290565b6000821982111561389857613898613a42565b500190565b60006bffffffffffffffffffffffff8083168185168083038211156138c4576138c4613a42565b01949350505050565b600082613903577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561394057613940613a42565b500290565b60008282101561395757613957613a42565b500390565b60006bffffffffffffffffffffffff8381169083168181101561398157613981613a42565b039392505050565b60005b838110156139a457818101518382015260200161398c565b838111156116615750506000910152565b600181811c908216806139c957607f821691505b60208210811415613a03577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613a3b57613a3b613a42565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6003811061163557611635613a7156fe3078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666663078666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var KeeperRegistryABI = KeeperRegistryMetaData.ABI diff --git a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go index e3f5b3c3511..18b61baed7f 100644 --- a/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go +++ b/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper/log_triggered_streams_lookup_wrapper.go @@ -42,8 +42,8 @@ type Log struct { } var LogTriggeredStreamsLookupMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_useArbitrumBlockNum\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blob\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verified\",\"type\":\"bytes\"}],\"name\":\"PerformingLogTriggerUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParam\",\"type\":\"string\"}],\"name\":\"setFeedParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"newFeeds\",\"type\":\"string[]\"}],\"name\":\"setFeedsHex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"timeParam\",\"type\":\"string\"}],\"name\":\"setTimeParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x610120604052604260a08181526080918291906200164e60c03990526200002a9060019081620000e5565b506040805180820190915260098152680cccacac892c890caf60bb1b60208201526002906200005a908262000261565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526003906200008c908262000261565b503480156200009a57600080fd5b506040516200169038038062001690833981016040819052620000bd9162000343565b6000805461ffff191692151561ff00191692909217610100911515919091021790556200037b565b82805482825590600052602060002090810192821562000130579160200282015b828111156200013057825182906200011f908262000261565b509160200191906001019062000106565b506200013e92915062000142565b5090565b808211156200013e57600062000159828262000163565b5060010162000142565b5080546200017190620001d2565b6000825580601f1062000182575050565b601f016020900490600052602060002090810190620001a29190620001a5565b50565b5b808211156200013e5760008155600101620001a6565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001e757607f821691505b6020821081036200020857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200025c57600081815260208120601f850160051c81016020861015620002375750805b601f850160051c820191505b81811015620002585782815560010162000243565b5050505b505050565b81516001600160401b038111156200027d576200027d620001bc565b62000295816200028e8454620001d2565b846200020e565b602080601f831160018114620002cd5760008415620002b45750858301515b600019600386901b1c1916600185901b17855562000258565b600085815260208120601f198616915b82811015620002fe57888601518255948401946001909101908401620002dd565b50858210156200031d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b805180151581146200033e57600080fd5b919050565b600080604083850312156200035757600080fd5b62000362836200032d565b915062000372602084016200032d565b90509250929050565b6112c3806200038b6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c8063642f6cef11610081578063afb28d1f1161005b578063afb28d1f14610196578063c98f10b01461019e578063fc735e99146101a657600080fd5b8063642f6cef146101465780639525d574146101635780639d6f1cc71461017657600080fd5b80634585e33b116100b25780634585e33b1461010d5780634b56a42e14610120578063601d5a711461013357600080fd5b806305e25131146100ce57806340691db4146100e3575b600080fd5b6100e16100dc3660046109cb565b6101b8565b005b6100f66100f1366004610a7c565b6101cf565b604051610104929190610b57565b60405180910390f35b6100e161011b366004610b7a565b61047f565b6100f661012e366004610bec565b61060e565b6100e1610141366004610ca9565b610664565b6000546101539060ff1681565b6040519015158152602001610104565b6100e1610171366004610ca9565b610670565b610189610184366004610cde565b61067c565b6040516101049190610cf7565b610189610728565b610189610735565b60005461015390610100900460ff1681565b80516101cb9060019060208401906107c8565b5050565b6000606060006101dd610742565b90507fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd61020d60c0870187610d11565b600081811061021e5761021e610d79565b90506020020135036103f757600061023960c0870187610d11565b600181811061024a5761024a610d79565b9050602002013560405160200161026391815260200190565b604051602081830303815290604052905060008180602001905181019061028a9190610da8565b9050600061029b60c0890189610d11565b60028181106102ac576102ac610d79565b905060200201356040516020016102c591815260200190565b60405160208183030381529060405290506000818060200190518101906102ec9190610da8565b905060006102fd60c08b018b610d11565b600381811061030e5761030e610d79565b9050602002013560405160200161032791815260200190565b604051602081830303815290604052905060008180602001905181019061034e9190610dea565b604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff821660608201529091506002906001906003908a90608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526103ee9594939291600401610ef3565b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f636f756c64206e6f742066696e64206d61746368696e67206576656e7420736960448201527f670000000000000000000000000000000000000000000000000000000000000060648201526084016103ee565b60008061048e83850185610bec565b915091506000806000838060200190518101906104ab9190610fb6565b6040805160208101909152600080825254939650919450925090610100900460ff16156105a1577309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe8760008151811061051557610515610d79565b60200260200101516040518263ffffffff1660e01b81526004016105399190610cf7565b6000604051808303816000875af1158015610558573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261059e9190810190610feb565b90505b327f299a03817e683a32b21e29e3ae3c31f1c9c773f7d532836d116b62a9281fbc9d8585856105ce610742565b8b6000815181106105e1576105e1610d79565b6020026020010151876040516105fc96959493929190611062565b60405180910390a25050505050505050565b60006060600084846040516020016106279291906110c2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052600193509150505b9250929050565b60036101cb828261119c565b60026101cb828261119c565b6001818154811061068c57600080fd5b9060005260206000200160009150905080546106a790610e05565b80601f01602080910402602001604051908101604052809291908181526020018280546106d390610e05565b80156107205780601f106106f557610100808354040283529160200191610720565b820191906000526020600020905b81548152906001019060200180831161070357829003601f168201915b505050505081565b600280546106a790610e05565b600380546106a790610e05565b6000805460ff16156107c357606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107be9190610da8565b905090565b504390565b82805482825590600052602060002090810192821561080e579160200282015b8281111561080e57825182906107fe908261119c565b50916020019190600101906107e8565b5061081a92915061081e565b5090565b8082111561081a576000610832828261083b565b5060010161081e565b50805461084790610e05565b6000825580601f10610857575050565b601f0160209004906000526020600020908101906108759190610878565b50565b5b8082111561081a5760008155600101610879565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156109035761090361088d565b604052919050565b600067ffffffffffffffff8211156109255761092561088d565b5060051b60200190565b600067ffffffffffffffff8211156109495761094961088d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261098657600080fd5b81356109996109948261092f565b6108bc565b8181528460208386010111156109ae57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208083850312156109de57600080fd5b823567ffffffffffffffff808211156109f657600080fd5b818501915085601f830112610a0a57600080fd5b8135610a186109948261090b565b81815260059190911b83018401908481019088831115610a3757600080fd5b8585015b83811015610a6f57803585811115610a535760008081fd5b610a618b89838a0101610975565b845250918601918601610a3b565b5098975050505050505050565b60008060408385031215610a8f57600080fd5b823567ffffffffffffffff80821115610aa757600080fd5b908401906101008287031215610abc57600080fd5b90925060208401359080821115610ad257600080fd5b50610adf85828601610975565b9150509250929050565b60005b83811015610b04578181015183820152602001610aec565b50506000910152565b60008151808452610b25816020860160208601610ae9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000610b726040830184610b0d565b949350505050565b60008060208385031215610b8d57600080fd5b823567ffffffffffffffff80821115610ba557600080fd5b818501915085601f830112610bb957600080fd5b813581811115610bc857600080fd5b866020828501011115610bda57600080fd5b60209290920196919550909350505050565b60008060408385031215610bff57600080fd5b823567ffffffffffffffff80821115610c1757600080fd5b818501915085601f830112610c2b57600080fd5b81356020610c3b6109948361090b565b82815260059290921b84018101918181019089841115610c5a57600080fd5b8286015b84811015610c9257803586811115610c765760008081fd5b610c848c86838b0101610975565b845250918301918301610c5e565b5096505086013592505080821115610ad257600080fd5b600060208284031215610cbb57600080fd5b813567ffffffffffffffff811115610cd257600080fd5b610b7284828501610975565b600060208284031215610cf057600080fd5b5035919050565b602081526000610d0a6020830184610b0d565b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610d4657600080fd5b83018035915067ffffffffffffffff821115610d6157600080fd5b6020019150600581901b360382131561065d57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610dba57600080fd5b5051919050565b805173ffffffffffffffffffffffffffffffffffffffff81168114610de557600080fd5b919050565b600060208284031215610dfc57600080fd5b610d0a82610dc1565b600181811c90821680610e1957607f821691505b602082108103610e52577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008154610e6581610e05565b808552602060018381168015610e825760018114610eba57610ee8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550610ee8565b866000528260002060005b85811015610ee05781548a8201860152908301908401610ec5565b890184019650505b505050505092915050565b60a081526000610f0660a0830188610e58565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015610f78577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0878403018552610f668383610e58565b94860194925060019182019101610f2d565b50508681036040880152610f8c818b610e58565b9450505050508460608401528281036080840152610faa8185610b0d565b98975050505050505050565b600080600060608486031215610fcb57600080fd5b8351925060208401519150610fe260408501610dc1565b90509250925092565b600060208284031215610ffd57600080fd5b815167ffffffffffffffff81111561101457600080fd5b8201601f8101841361102557600080fd5b80516110336109948261092f565b81815285602083850101111561104857600080fd5b611059826020830160208601610ae9565b95945050505050565b86815285602082015273ffffffffffffffffffffffffffffffffffffffff8516604082015283606082015260c0608082015260006110a360c0830185610b0d565b82810360a08401526110b58185610b0d565b9998505050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015611137577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552611125868351610b0d565b955093820193908201906001016110eb565b5050858403818701525050506110598185610b0d565b601f82111561119757600081815260208120601f850160051c810160208610156111745750805b601f850160051c820191505b8181101561119357828155600101611180565b5050505b505050565b815167ffffffffffffffff8111156111b6576111b661088d565b6111ca816111c48454610e05565b8461114d565b602080601f83116001811461121d57600084156111e75750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611193565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561126a5788860151825594840194600190910190840161124b565b50858210156112a657878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", + ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_useArbitrumBlockNum\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"_verify\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParamKey\",\"type\":\"string\"},{\"internalType\":\"string[]\",\"name\":\"feeds\",\"type\":\"string[]\"},{\"internalType\":\"string\",\"name\":\"timeParamKey\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"time\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"StreamsLookup\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"}],\"name\":\"LimitOrderExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"orderId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"exchange\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"blob\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"verified\",\"type\":\"bytes\"}],\"name\":\"PerformingLogTriggerUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"values\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"checkCallback\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feedParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"feedsHex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"feedParam\",\"type\":\"string\"}],\"name\":\"setFeedParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"newFeeds\",\"type\":\"string[]\"}],\"name\":\"setFeedsHex\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"timeParam\",\"type\":\"string\"}],\"name\":\"setTimeParamKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"start\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeParamKey\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"useArbitrumBlockNum\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x610120604052604260a08181526080918291906200179660c03990526200002a9060019081620000e8565b506040805180820190915260098152680cccacac892c890caf60bb1b60208201526002906200005a908262000264565b5060408051808201909152600b81526a313637b1b5a73ab6b132b960a91b60208201526003906200008c908262000264565b503480156200009a57600080fd5b50604051620017d8380380620017d8833981016040819052620000bd9162000346565b6000805461ffff191692151561ff00191692909217610100911515919091021781556004556200037e565b82805482825590600052602060002090810192821562000133579160200282015b8281111562000133578251829062000122908262000264565b509160200191906001019062000109565b506200014192915062000145565b5090565b80821115620001415760006200015c828262000166565b5060010162000145565b5080546200017490620001d5565b6000825580601f1062000185575050565b601f016020900490600052602060002090810190620001a59190620001a8565b50565b5b80821115620001415760008155600101620001a9565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ea57607f821691505b6020821081036200020b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200025f57600081815260208120601f850160051c810160208610156200023a5750805b601f850160051c820191505b818110156200025b5782815560010162000246565b5050505b505050565b81516001600160401b03811115620002805762000280620001bf565b6200029881620002918454620001d5565b8462000211565b602080601f831160018114620002d05760008415620002b75750858301515b600019600386901b1c1916600185901b1785556200025b565b600085815260208120601f198616915b828110156200030157888601518255948401946001909101908401620002e0565b5085821015620003205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b805180151581146200034157600080fd5b919050565b600080604083850312156200035a57600080fd5b620003658362000330565b9150620003756020840162000330565b90509250929050565b611408806200038e6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c8063642f6cef1161008c578063afb28d1f11610066578063afb28d1f146101c3578063be9a6555146101cb578063c98f10b0146101d3578063fc735e99146101db57600080fd5b8063642f6cef146101735780639525d574146101905780639d6f1cc7146101a357600080fd5b80634b56a42e116100bd5780634b56a42e14610136578063601d5a711461014957806361bc221a1461015c57600080fd5b806305e25131146100e457806340691db4146100f95780634585e33b14610123575b600080fd5b6100f76100f2366004610ac8565b6101ed565b005b61010c610107366004610b79565b610204565b60405161011a929190610c54565b60405180910390f35b6100f7610131366004610c77565b6104da565b61010c610144366004610ce9565b6106d8565b6100f7610157366004610da6565b61072e565b61016560045481565b60405190815260200161011a565b6000546101809060ff1681565b604051901515815260200161011a565b6100f761019e366004610da6565b61073a565b6101b66101b1366004610ddb565b610746565b60405161011a9190610df4565b6101b66107f2565b6100f76107ff565b6101b6610832565b60005461018090610100900460ff1681565b80516102009060019060208401906108c5565b5050565b60006060600061021261083f565b90507fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd61024260c0870187610e0e565b600081811061025357610253610e76565b905060200201350361045257600061026e60c0870187610e0e565b600181811061027f5761027f610e76565b9050602002013560405160200161029891815260200190565b60405160208183030381529060405290506000818060200190518101906102bf9190610ea5565b905060006102d060c0890189610e0e565b60028181106102e1576102e1610e76565b905060200201356040516020016102fa91815260200190565b60405160208183030381529060405290506000818060200190518101906103219190610ea5565b9050600061033260c08b018b610e0e565b600381811061034357610343610e76565b9050602002013560405160200161035c91815260200190565b60405160208183030381529060405290506000818060200190518101906103839190610ee7565b604080516020810188905290810185905273ffffffffffffffffffffffffffffffffffffffff821660608201527fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd60808201529091506002906001906003908a9060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527ff055e4a20000000000000000000000000000000000000000000000000000000082526104499594939291600401610ff0565b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f636f756c64206e6f742066696e64206d61746368696e67206576656e7420736960448201527f67000000000000000000000000000000000000000000000000000000000000006064820152608401610449565b6000806104e983850185610ce9565b915091506000806000808480602001905181019061050791906110b3565b6040805160208101909152600080825254949850929650909450925090610100900460ff1615610600577309dff56a4ff44e0f4436260a04f5cfa65636a48173ffffffffffffffffffffffffffffffffffffffff16638e760afe8860008151811061057457610574610e76565b60200260200101516040518263ffffffff1660e01b81526004016105989190610df4565b6000604051808303816000875af11580156105b7573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105fd91908101906110f0565b90505b60045461060e906001611167565b6004557f2e00161baa7e3ee28260d12a08ade832b4160748111950f092fc0b921ac6a933820161066a576040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a45b327f299a03817e683a32b21e29e3ae3c31f1c9c773f7d532836d116b62a9281fbc9d86868661069761083f565b8c6000815181106106aa576106aa610e76565b6020026020010151876040516106c5969594939291906111a7565b60405180910390a2505050505050505050565b60006060600084846040516020016106f1929190611207565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052600193509150505b9250929050565b600361020082826112e1565b600261020082826112e1565b6001818154811061075657600080fd5b90600052602060002001600091509050805461077190610f02565b80601f016020809104026020016040519081016040528092919081815260200182805461079d90610f02565b80156107ea5780601f106107bf576101008083540402835291602001916107ea565b820191906000526020600020905b8154815290600101906020018083116107cd57829003601f168201915b505050505081565b6002805461077190610f02565b6040516000906064906001907fd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd908490a4565b6003805461077190610f02565b6000805460ff16156108c057606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bb9190610ea5565b905090565b504390565b82805482825590600052602060002090810192821561090b579160200282015b8281111561090b57825182906108fb90826112e1565b50916020019190600101906108e5565b5061091792915061091b565b5090565b8082111561091757600061092f8282610938565b5060010161091b565b50805461094490610f02565b6000825580601f10610954575050565b601f0160209004906000526020600020908101906109729190610975565b50565b5b808211156109175760008155600101610976565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a0057610a0061098a565b604052919050565b600067ffffffffffffffff821115610a2257610a2261098a565b5060051b60200190565b600067ffffffffffffffff821115610a4657610a4661098a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610a8357600080fd5b8135610a96610a9182610a2c565b6109b9565b818152846020838601011115610aab57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020808385031215610adb57600080fd5b823567ffffffffffffffff80821115610af357600080fd5b818501915085601f830112610b0757600080fd5b8135610b15610a9182610a08565b81815260059190911b83018401908481019088831115610b3457600080fd5b8585015b83811015610b6c57803585811115610b505760008081fd5b610b5e8b89838a0101610a72565b845250918601918601610b38565b5098975050505050505050565b60008060408385031215610b8c57600080fd5b823567ffffffffffffffff80821115610ba457600080fd5b908401906101008287031215610bb957600080fd5b90925060208401359080821115610bcf57600080fd5b50610bdc85828601610a72565b9150509250929050565b60005b83811015610c01578181015183820152602001610be9565b50506000910152565b60008151808452610c22816020860160208601610be6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8215158152604060208201526000610c6f6040830184610c0a565b949350505050565b60008060208385031215610c8a57600080fd5b823567ffffffffffffffff80821115610ca257600080fd5b818501915085601f830112610cb657600080fd5b813581811115610cc557600080fd5b866020828501011115610cd757600080fd5b60209290920196919550909350505050565b60008060408385031215610cfc57600080fd5b823567ffffffffffffffff80821115610d1457600080fd5b818501915085601f830112610d2857600080fd5b81356020610d38610a9183610a08565b82815260059290921b84018101918181019089841115610d5757600080fd5b8286015b84811015610d8f57803586811115610d735760008081fd5b610d818c86838b0101610a72565b845250918301918301610d5b565b5096505086013592505080821115610bcf57600080fd5b600060208284031215610db857600080fd5b813567ffffffffffffffff811115610dcf57600080fd5b610c6f84828501610a72565b600060208284031215610ded57600080fd5b5035919050565b602081526000610e076020830184610c0a565b9392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e4357600080fd5b83018035915067ffffffffffffffff821115610e5e57600080fd5b6020019150600581901b360382131561072757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610eb757600080fd5b5051919050565b805173ffffffffffffffffffffffffffffffffffffffff81168114610ee257600080fd5b919050565b600060208284031215610ef957600080fd5b610e0782610ebe565b600181811c90821680610f1657607f821691505b602082108103610f4f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60008154610f6281610f02565b808552602060018381168015610f7f5760018114610fb757610fe5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b8901019550610fe5565b866000528260002060005b85811015610fdd5781548a8201860152908301908401610fc2565b890184019650505b505050505092915050565b60a08152600061100360a0830188610f55565b6020838203818501528188548084528284019150828160051b8501018a6000528360002060005b83811015611075577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526110638383610f55565b9486019492506001918201910161102a565b50508681036040880152611089818b610f55565b94505050505084606084015282810360808401526110a78185610c0a565b98975050505050505050565b600080600080608085870312156110c957600080fd5b84519350602085015192506110e060408601610ebe565b6060959095015193969295505050565b60006020828403121561110257600080fd5b815167ffffffffffffffff81111561111957600080fd5b8201601f8101841361112a57600080fd5b8051611138610a9182610a2c565b81815285602083850101111561114d57600080fd5b61115e826020830160208601610be6565b95945050505050565b808201808211156111a1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b92915050565b86815285602082015273ffffffffffffffffffffffffffffffffffffffff8516604082015283606082015260c0608082015260006111e860c0830185610c0a565b82810360a08401526111fa8185610c0a565b9998505050505050505050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561127c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261126a868351610c0a565b95509382019390820190600101611230565b50508584038187015250505061115e8185610c0a565b601f8211156112dc57600081815260208120601f850160051c810160208610156112b95750805b601f850160051c820191505b818110156112d8578281556001016112c5565b5050505b505050565b815167ffffffffffffffff8111156112fb576112fb61098a565b61130f816113098454610f02565b84611292565b602080601f831160018114611362576000841561132c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556112d8565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156113af57888601518255948401946001909101908401611390565b50858210156113eb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000810000a307834353534343832643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030", } var LogTriggeredStreamsLookupABI = LogTriggeredStreamsLookupMetaData.ABI @@ -205,6 +205,28 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCallerSession) CheckC return _LogTriggeredStreamsLookup.Contract.CheckCallback(&_LogTriggeredStreamsLookup.CallOpts, values, extraData) } +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _LogTriggeredStreamsLookup.contract.Call(opts, &out, "counter") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupSession) Counter() (*big.Int, error) { + return _LogTriggeredStreamsLookup.Contract.Counter(&_LogTriggeredStreamsLookup.CallOpts) +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCallerSession) Counter() (*big.Int, error) { + return _LogTriggeredStreamsLookup.Contract.Counter(&_LogTriggeredStreamsLookup.CallOpts) +} + func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupCaller) FeedParamKey(opts *bind.CallOpts) (string, error) { var out []interface{} err := _LogTriggeredStreamsLookup.contract.Call(opts, &out, "feedParamKey") @@ -375,6 +397,163 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupTransactorSession) Se return _LogTriggeredStreamsLookup.Contract.SetTimeParamKey(&_LogTriggeredStreamsLookup.TransactOpts, timeParam) } +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupTransactor) Start(opts *bind.TransactOpts) (*types.Transaction, error) { + return _LogTriggeredStreamsLookup.contract.Transact(opts, "start") +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupSession) Start() (*types.Transaction, error) { + return _LogTriggeredStreamsLookup.Contract.Start(&_LogTriggeredStreamsLookup.TransactOpts) +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupTransactorSession) Start() (*types.Transaction, error) { + return _LogTriggeredStreamsLookup.Contract.Start(&_LogTriggeredStreamsLookup.TransactOpts) +} + +type LogTriggeredStreamsLookupLimitOrderExecutedIterator struct { + Event *LogTriggeredStreamsLookupLimitOrderExecuted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LogTriggeredStreamsLookupLimitOrderExecutedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LogTriggeredStreamsLookupLimitOrderExecuted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(LogTriggeredStreamsLookupLimitOrderExecuted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *LogTriggeredStreamsLookupLimitOrderExecutedIterator) Error() error { + return it.fail +} + +func (it *LogTriggeredStreamsLookupLimitOrderExecutedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LogTriggeredStreamsLookupLimitOrderExecuted struct { + OrderId *big.Int + Amount *big.Int + Exchange common.Address + Raw types.Log +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) FilterLimitOrderExecuted(opts *bind.FilterOpts, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (*LogTriggeredStreamsLookupLimitOrderExecutedIterator, error) { + + var orderIdRule []interface{} + for _, orderIdItem := range orderId { + orderIdRule = append(orderIdRule, orderIdItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var exchangeRule []interface{} + for _, exchangeItem := range exchange { + exchangeRule = append(exchangeRule, exchangeItem) + } + + logs, sub, err := _LogTriggeredStreamsLookup.contract.FilterLogs(opts, "LimitOrderExecuted", orderIdRule, amountRule, exchangeRule) + if err != nil { + return nil, err + } + return &LogTriggeredStreamsLookupLimitOrderExecutedIterator{contract: _LogTriggeredStreamsLookup.contract, event: "LimitOrderExecuted", logs: logs, sub: sub}, nil +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) WatchLimitOrderExecuted(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupLimitOrderExecuted, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (event.Subscription, error) { + + var orderIdRule []interface{} + for _, orderIdItem := range orderId { + orderIdRule = append(orderIdRule, orderIdItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var exchangeRule []interface{} + for _, exchangeItem := range exchange { + exchangeRule = append(exchangeRule, exchangeItem) + } + + logs, sub, err := _LogTriggeredStreamsLookup.contract.WatchLogs(opts, "LimitOrderExecuted", orderIdRule, amountRule, exchangeRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LogTriggeredStreamsLookupLimitOrderExecuted) + if err := _LogTriggeredStreamsLookup.contract.UnpackLog(event, "LimitOrderExecuted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) ParseLimitOrderExecuted(log types.Log) (*LogTriggeredStreamsLookupLimitOrderExecuted, error) { + event := new(LogTriggeredStreamsLookupLimitOrderExecuted) + if err := _LogTriggeredStreamsLookup.contract.UnpackLog(event, "LimitOrderExecuted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type LogTriggeredStreamsLookupPerformingLogTriggerUpkeepIterator struct { Event *LogTriggeredStreamsLookupPerformingLogTriggerUpkeep @@ -510,6 +689,8 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookupFilterer) ParsePerfor func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { + case _LogTriggeredStreamsLookup.abi.Events["LimitOrderExecuted"].ID: + return _LogTriggeredStreamsLookup.ParseLimitOrderExecuted(log) case _LogTriggeredStreamsLookup.abi.Events["PerformingLogTriggerUpkeep"].ID: return _LogTriggeredStreamsLookup.ParsePerformingLogTriggerUpkeep(log) @@ -518,6 +699,10 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) ParseLog(log types. } } +func (LogTriggeredStreamsLookupLimitOrderExecuted) Topic() common.Hash { + return common.HexToHash("0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd") +} + func (LogTriggeredStreamsLookupPerformingLogTriggerUpkeep) Topic() common.Hash { return common.HexToHash("0x299a03817e683a32b21e29e3ae3c31f1c9c773f7d532836d116b62a9281fbc9d") } @@ -529,6 +714,8 @@ func (_LogTriggeredStreamsLookup *LogTriggeredStreamsLookup) Address() common.Ad type LogTriggeredStreamsLookupInterface interface { CheckCallback(opts *bind.CallOpts, values [][]byte, extraData []byte) (bool, []byte, error) + Counter(opts *bind.CallOpts) (*big.Int, error) + FeedParamKey(opts *bind.CallOpts) (string, error) FeedsHex(opts *bind.CallOpts, arg0 *big.Int) (string, error) @@ -549,6 +736,14 @@ type LogTriggeredStreamsLookupInterface interface { SetTimeParamKey(opts *bind.TransactOpts, timeParam string) (*types.Transaction, error) + Start(opts *bind.TransactOpts) (*types.Transaction, error) + + FilterLimitOrderExecuted(opts *bind.FilterOpts, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (*LogTriggeredStreamsLookupLimitOrderExecutedIterator, error) + + WatchLimitOrderExecuted(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupLimitOrderExecuted, orderId []*big.Int, amount []*big.Int, exchange []common.Address) (event.Subscription, error) + + ParseLimitOrderExecuted(log types.Log) (*LogTriggeredStreamsLookupLimitOrderExecuted, error) + FilterPerformingLogTriggerUpkeep(opts *bind.FilterOpts, from []common.Address) (*LogTriggeredStreamsLookupPerformingLogTriggerUpkeepIterator, error) WatchPerformingLogTriggerUpkeep(opts *bind.WatchOpts, sink chan<- *LogTriggeredStreamsLookupPerformingLogTriggerUpkeep, from []common.Address) (event.Subscription, error) diff --git a/core/gethwrappers/generated/operator_factory/operator_factory.go b/core/gethwrappers/generated/operator_factory/operator_factory.go index a62e1aaa7a1..b062f6b01a3 100644 --- a/core/gethwrappers/generated/operator_factory/operator_factory.go +++ b/core/gethwrappers/generated/operator_factory/operator_factory.go @@ -31,8 +31,8 @@ var ( ) var OperatorFactoryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AuthorizedForwarderCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OperatorCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"created\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deployNewForwarderAndTransferOwnership\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperatorAndForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051615bd5380380615bd58339818101604052602081101561003357600080fd5b5051606081901b6001600160601b0319166080526001600160a01b0316615b556100806000398061026752806102c752806103c5528061056d528061072d528061087e5250615b556000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80633babafdb1161005b5780633babafdb14610181578063d42efd8314610189578063d689d095146101d0578063f4adb6e11461025d5761007d565b8063165d35e114610082578063181f5a77146100b357806332f01eae14610130575b600080fd5b61008a610265565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100bb610289565b6040805160208082528351818301528351919283929083019185019080838360005b838110156100f55781810151838201526020016100dd565b50505050905090810190601f1680156101225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101386102c0565b604051808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b61008a610559565b6101bc6004803603602081101561019f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166106fd565b604080519115158252519081900360200190f35b61008a600480360360408110156101e657600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561021e57600080fd5b82018360208201111561023057600080fd5b8035906020019184600183028401116401000000008311171561025257600080fd5b509092509050610728565b61008a610879565b7f000000000000000000000000000000000000000000000000000000000000000081565b60408051808201909152601581527f4f70657261746f72466163746f727920312e302e300000000000000000000000602082015290565b60008060007f0000000000000000000000000000000000000000000000000000000000000000336040516102f39061096b565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604080519182900301906000f080158015610333573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a460408051600080825260208201909252905060007f00000000000000000000000000000000000000000000000000000000000000003084846040516103f390610979565b808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610481578181015183820152602001610469565b50505050905090810190601f1680156104ae5780820380516001836020036101000a031916815260200191505b5095505050505050604051809103906000f0801580156104d2573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919350909150509091565b6040805160008082526020820190925260007f00000000000000000000000000000000000000000000000000000000000000003360008460405161059c90610979565b808573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561062a578181015183820152602001610612565b50505050905090810190601f1680156106575780820380516001836020036101000a031916815260200191505b5095505050505050604051809103906000f08015801561067b573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a491505090565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6000807f00000000000000000000000000000000000000000000000000000000000000003386868660405161075c90610979565b73ffffffffffffffffffffffffffffffffffffffff808716825285811660208301528416604082015260806060820181815290820183905260a082018484808284376000838201819052604051601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909301819003995097509095505050505050f0801580156107f5573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f0000000000000000000000000000000000000000000000000000000000000000336040516108aa9061096b565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604080519182900301906000f0801580156108ea573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4905090565b613e8c806200098883390190565b61133580620048148339019056fe60a060405260016006553480156200001657600080fd5b5060405162003e8c38038062003e8c833981810160405260408110156200003c57600080fd5b508051602090910151808060006001600160a01b038216620000a5576040805162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000d857620000d881620000f2565b5050505060601b6001600160601b031916608052620001a3565b6001600160a01b03811633141562000151576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60805160601c613ca8620001e460003980610fde528061120a52806122c652806124d052806129c15280612e0352806131f252806136bb5250613ca86000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b14610c3c578063f3fef3a314610c7c578063fa00763a14610cc2578063fc4a03ed14610d0257610196565b8063a4c0ed3614610a8c578063eb007d9914610b61578063ee56997b14610bbf57610196565b806379ba5097116100bb57806379ba5097146109c35780638da5cb5b146109d8578063902fc370146109ed57610196565b80636ae0bc76146107cf5780636bd59ec0146108a35780636ee4d5531461096557610196565b80633c6d41b9116101435780634ab0d1901161011d5780634ab0d1901461065757806350188301146106eb5780635ffa62881461070057610196565b80633c6d41b9146104085780633ec5bc14146104e1578063404299461461057457610196565b8063181f5a7711610174578063181f5a77146102f25780632408afaa1461037c57806325cb5bc0146103e157610196565b806301994b991461019b578063033f49f71461021a578063165d35e1146102b4575b600080fd5b3480156101a757600080fd5b50610218600480360360208110156101be57600080fd5b8101906020810181356401000000008111156101d957600080fd5b8201836020820111156101eb57600080fd5b8035906020019184602083028401116401000000008311171561020d57600080fd5b509092509050610dd1565b005b34801561022657600080fd5b506102186004803603604081101561023d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561027557600080fd5b82018360208201111561028757600080fd5b803590602001918460018302840111640100000000831117156102a957600080fd5b509092509050610fd3565b3480156102c057600080fd5b506102c9611208565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156102fe57600080fd5b5061030761122c565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610341578181015183820152602001610329565b50505050905090810190601f16801561036e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561038857600080fd5b50610391611263565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156103cd5781810151838201526020016103b5565b505050509050019250505060405180910390f35b3480156103ed57600080fd5b506103f66112d2565b60408051918252519081900360200190f35b34801561041457600080fd5b50610218600480360360e081101561042b57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516916020810135916040820135917fffffffff000000000000000000000000000000000000000000000000000000006060820135169160808201359160a08101359181019060e0810160c08201356401000000008111156104a257600080fd5b8201836020820111156104b457600080fd5b803590602001918460018302840111640100000000831117156104d657600080fd5b5090925090506112d8565b3480156104ed57600080fd5b506102186004803603604081101561050457600080fd5b81019060208101813564010000000081111561051f57600080fd5b82018360208201111561053157600080fd5b8035906020019184602083028401116401000000008311171561055357600080fd5b91935091503573ffffffffffffffffffffffffffffffffffffffff1661149c565b34801561058057600080fd5b50610218600480360361010081101561059857600080fd5b73ffffffffffffffffffffffffffffffffffffffff8235811692602081013592604082013592606083013516917fffffffff000000000000000000000000000000000000000000000000000000006080820135169160a08201359160c081013591810190610100810160e082013564010000000081111561061857600080fd5b82018360208201111561062a57600080fd5b8035906020019184600183028401116401000000008311171561064c57600080fd5b5090925090506115ea565b34801561066357600080fd5b506106d7600480360360c081101561067a57600080fd5b5080359060208101359073ffffffffffffffffffffffffffffffffffffffff604082013516907fffffffff000000000000000000000000000000000000000000000000000000006060820135169060808101359060a001356117af565b604080519115158252519081900360200190f35b3480156106f757600080fd5b506103f6611ae8565b34801561070c57600080fd5b506102186004803603604081101561072357600080fd5b81019060208101813564010000000081111561073e57600080fd5b82018360208201111561075057600080fd5b8035906020019184602083028401116401000000008311171561077257600080fd5b91939092909160208101903564010000000081111561079057600080fd5b8201836020820111156107a257600080fd5b803590602001918460208302840111640100000000831117156107c457600080fd5b509092509050611af7565b3480156107db57600080fd5b506106d7600480360360c08110156107f257600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516917fffffffff00000000000000000000000000000000000000000000000000000000606082013516916080820135919081019060c0810160a082013564010000000081111561086457600080fd5b82018360208201111561087657600080fd5b8035906020019184600183028401116401000000008311171561089857600080fd5b509092509050611b80565b610218600480360360408110156108b957600080fd5b8101906020810181356401000000008111156108d457600080fd5b8201836020820111156108e657600080fd5b8035906020019184602083028401116401000000008311171561090857600080fd5b91939092909160208101903564010000000081111561092657600080fd5b82018360208201111561093857600080fd5b8035906020019184602083028401116401000000008311171561095a57600080fd5b509092509050611f85565b34801561097157600080fd5b506102186004803603608081101561098857600080fd5b508035906020810135907fffffffff00000000000000000000000000000000000000000000000000000000604082013516906060013561211c565b3480156109cf57600080fd5b50610218612341565b3480156109e457600080fd5b506102c9612447565b3480156109f957600080fd5b506106d760048036036060811015610a1057600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691602081013591810190606081016040820135640100000000811115610a4d57600080fd5b820183602082011115610a5f57600080fd5b80359060200191846001830284011164010000000083111715610a8157600080fd5b509092509050612463565b348015610a9857600080fd5b5061021860048036036060811015610aaf57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691602081013591810190606081016040820135640100000000811115610aec57600080fd5b820183602082011115610afe57600080fd5b80359060200191846001830284011164010000000083111715610b2057600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506125c9945050505050565b348015610b6d57600080fd5b5061021860048036036080811015610b8457600080fd5b508035906020810135907fffffffff0000000000000000000000000000000000000000000000000000000060408201351690606001356127cb565b348015610bcb57600080fd5b5061021860048036036020811015610be257600080fd5b810190602081018135640100000000811115610bfd57600080fd5b820183602082011115610c0f57600080fd5b80359060200191846020830284011164010000000083111715610c3157600080fd5b509092509050612a3d565b348015610c4857600080fd5b5061021860048036036020811015610c5f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612d84565b348015610c8857600080fd5b5061021860048036036040811015610c9f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612d98565b348015610cce57600080fd5b506106d760048036036020811015610ce557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612ec4565b348015610d0e57600080fd5b5061021860048036036040811015610d2557600080fd5b810190602081018135640100000000811115610d4057600080fd5b820183602082011115610d5257600080fd5b80359060200191846020830284011164010000000083111715610d7457600080fd5b919390929091602081019035640100000000811115610d9257600080fd5b820183602082011115610da457600080fd5b80359060200191846020830284011164010000000083111715610dc657600080fd5b509092509050612eef565b610dd9613128565b610e4457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b60005b81811015610fce57600160056000858585818110610e6157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550828282818110610edb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a2828282818110610f4657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610faa57600080fd5b505af1158015610fbe573d6000803e3d6000fd5b505060019092019150610e479050565b505050565b610fdb61315e565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561109757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b00000000000000000000000000604482015290519081900360640190fd5b6110b68473ffffffffffffffffffffffffffffffffffffffff166131e6565b61112157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e7472616374000000000000604482015290519081900360640190fd5b60008473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284376040519201945060009350909150508083038183865af19150503d806000811461118c576040519150601f19603f3d011682016040523d82523d6000602084013e611191565b606091505b505090508061120157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c65640000000000000000000000604482015290519081900360640190fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000090565b60408051808201909152600e81527f4f70657261746f7220312e302e30000000000000000000000000000000000000602082015290565b606060018054806020026020016040519081016040528092919081815260200182805480156112c857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161129d575b5050505050905090565b61012c81565b6112e0611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461137957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b60008061138a8a8a8c8a8a8a6131ec565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051808a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001858152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039c50909a5050505050505050505050a250505050505050505050565b6114a461315e565b60005b828110156115e4576000600560008686858181106114c157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555083838281811061153b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f2fde38b836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156115c057600080fd5b505af11580156115d4573d6000803e3d6000fd5b5050600190920191506114a79050565b50505050565b6115f2611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461168b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b60008061169c8b8b8a8a8a8a6131ec565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051808a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001858152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039c50909a5050505050505050505050a25050505050505050505050565b60006117b9613498565b600087815260046020526040902054879060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001661185a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c6964207265717565737449640000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff16156118f157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e7472616374000000000000604482015290519081900360640190fd5b6119008989898989600161350c565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a101561199d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f75676820676173604482015290519081900360640190fd5b60408051602481018b9052604480820187905282518083039091018152606490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000008a161781529151815160009373ffffffffffffffffffffffffffffffffffffffff8c169392918291908083835b60208310611a7057805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611a33565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ad2576040519150601f19603f3d011682016040523d82523d6000602084013e611ad7565b606091505b50909b9a5050505050505050505050565b6000611af261369a565b905090565b611aff613128565b611b6a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b611b748484610dd1565b6115e484848484612eef565b6000611b8a613498565b600088815260046020526040902054889060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016611c2b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c6964207265717565737449640000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611cc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e7472616374000000000000604482015290519081900360640190fd5b8985856020811015611d3557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e2033322062797465730000000000604482015290519081900360640190fd5b8135838114611da557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d7573742062652072657175657374496400000000604482015290519081900360640190fd5b611db48e8e8e8e8e600261350c565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611e5157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f75676820676173604482015290519081900360640190fd5b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b60405160200180847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526004018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310611f0757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611eca565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611f69576040519150601f19603f3d011682016040523d82523d6000602084013e611f6e565b606091505b509098505050505050505050979650505050505050565b8215801590611f9357508281145b611ffe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e677468287329000000000000000000604482015290519081900360640190fd5b3460005b848110156120ae57600084848381811061201857fe5b905060200201359050612034818461377890919063ffffffff16565b925086868381811061204257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156120a4573d6000803e3d6000fd5b5050600101612002565b50801561120157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e74000000000000000000000000000000604482015290519081900360640190fd5b600061212a843385856137ef565b60008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146121d257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b4282111561224157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f74206578706972656400000000000000000000604482015290519081900360640190fd5b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815233600482015260248101869052905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b15801561230e57600080fd5b505af1158015612322573d6000803e3d6000fd5b505050506040513d602081101561233857600080fd5b50505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146123c757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015290519081900360640190fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60025473ffffffffffffffffffffffffffffffffffffffff1690565b600061246d61315e565b838061247761369a565b10156124ce576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613c676035913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0878787876040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050602060405180830381600087803b15801561259357600080fd5b505af11580156125a7573d6000803e3d6000fd5b505050506040513d60208110156125bd57600080fd5b50519695505050505050565b6125d1611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461266a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b6020810151819061267b8183613874565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106126ee57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016126b1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461274e576040519150601f19603f3d011682016040523d82523d6000602084013e612753565b606091505b50509050806127c357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f2063726561746520726571756573740000000000000000604482015290519081900360640190fd5b505050505050565b60003385604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000612825853386866137ef565b60008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146128cd57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b4283111561293c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f74206578706972656400000000000000000000604482015290519081900360640190fd5b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815233600482015260248101879052905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b158015612a0957600080fd5b505af1158015612a1d573d6000803e3d6000fd5b505050506040513d6020811015612a3357600080fd5b5050505050505050565b612a45613128565b612ab057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b80612b1c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e6465720000000000604482015290519081900360640190fd5b60015460005b81811015612ba357600080600060018481548110612b3c57fe5b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101612b22565b5060005b82811015612cd257600080858584818110612bbe57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168352508101919091526040016000205460ff1615612c5d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e6465727300604482015290519081900360640190fd5b6001600080868685818110612c6e57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff1683525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101612ba7565b50612cdf60018484613bd2565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405180806020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252858582818152602001925060200280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b612d8c61315e565b612d95816139e5565b50565b612da061315e565b8080612daa61369a565b1015612e01576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613c676035913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612e9257600080fd5b505af1158015612ea6573d6000803e3d6000fd5b505050506040513d6020811015612ebc57600080fd5b5051610fce57fe5b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b612ef7613128565b612f6257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040518080602001806020018473ffffffffffffffffffffffffffffffffffffffff1681526020018381038352888882818152602001925060200280828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091018481038352868152602090810191508790870280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003995090975050505050505050a160005b838110156112015784848281811061306657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040180806020018281038252848482818152602001925060200280828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b15801561310457600080fd5b505af1158015613118573d6000803e3d6000fd5b5050600190920191506130529050565b600061313333612ec4565b80611af2575033613142612447565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146131e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b565b3b151590565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156132ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b00000000000000000000000000604482015290519081900360640190fd5b6040805160608b901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083019190915260348083018990528351808403909101815260549092018352815191810191909120600081815260049092529190205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016156133a357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e69717565204944000000000000000000000000604482015290519081900360640190fd5b6133af4261012c613ae1565b915060006133bf898989866137ef565b905060405180604001604052808260ff191681526020016133df87613b5c565b60ff90811690915260008681526004602090815260409091208351815494909201519092167f01000000000000000000000000000000000000000000000000000000000000000260089190911c7fff00000000000000000000000000000000000000000000000000000000000000909316929092177effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919091179055600654613488908a613ae1565b6006555050965096945050505050565b6134a133612ec4565b6131e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e6465720000000000000000000000604482015290519081900360640190fd5b600061351a868686866137ef565b60008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146135c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b6135cb82613b5c565b60008881526004602052604090205460ff9182167f0100000000000000000000000000000000000000000000000000000000000000909104909116111561367357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d617463680000000000000000604482015290519081900360640190fd5b6006546136809087613778565b600655505050600093845250506004602052506040812055565b6000806136b3600160065461377890919063ffffffff16565b9050613772817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561374057600080fd5b505afa158015613754573d6000803e3d6000fd5b505050506040513d602081101561376a57600080fd5b505190613778565b91505090565b6000828211156137e957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6040805160208082019690965260609490941b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016848201527fffffffff000000000000000000000000000000000000000000000000000000009290921660548401526058808401919091528151808403909101815260789092019052805191012090565b8051604411156138e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e67746800000000000000000000604482015290519081900360640190fd5b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b900000000000000000000000000000000000000000000000000000000148061397657507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b6139e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e730000604482015290519081900360640190fd5b5050565b73ffffffffffffffffffffffffffffffffffffffff8116331415613a6a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600082820183811015613b5557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60006101008210613bce57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e756d62657220746f6f2062696720746f206361737400000000000000000000604482015290519081900360640190fd5b5090565b828054828255906000526020600020908101928215613c4a579160200282015b82811115613c4a5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190613bf2565b50613bce9291505b80821115613bce5760008155600101613c5256fe416d6f756e74207265717565737465642069732067726561746572207468616e20776974686472617761626c652062616c616e6365a164736f6c6343000706000a60a06040523480156200001157600080fd5b506040516200133538038062001335833981810160405260808110156200003757600080fd5b8151602083015160408085015160608601805192519496939591949391820192846401000000008211156200006b57600080fd5b9083019060208201858111156200008157600080fd5b82516401000000008111828201881017156200009c57600080fd5b82525081516020918201929091019080838360005b83811015620000cb578181015183820152602001620000b1565b50505050905090810190601f168015620000f95780820380516001836020036101000a031916815260200191505b50604052508491508390506001600160a01b03821662000160576040805162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200019357620001938162000286565b50506001600160a01b038416620001a957600080fd5b6001600160601b0319606085901b166080526001600160a01b038216156200027c57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040518080602001828103825283818151815260200191508051906020019080838360005b838110156200024057818101518382015260200162000226565b50505050905090810190601f1680156200026e5780820380516001836020036101000a031916815260200191505b509250505060405180910390a35b5050505062000336565b6001600160a01b038116331415620002e5576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60805160601c610fdc6200035960003980610491528061061d5250610fdc6000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80636fadcf7211610081578063ee56997b1161005b578063ee56997b1461038d578063f2fde38b146103fd578063fa00763a14610430576100c9565b80636fadcf72146102f057806379ba50971461037d5780638da5cb5b14610385576100c9565b8063181f5a77116100b2578063181f5a771461018e5780632408afaa1461020b5780634d3e232314610263576100c9565b8063033f49f7146100ce578063165d35e11461015d575b600080fd5b61015b600480360360408110156100e457600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561011c57600080fd5b82018360208201111561012e57600080fd5b8035906020019184600183028401116401000000008311171561015057600080fd5b509092509050610477565b005b61016561048f565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101966104b3565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101d05781810151838201526020016101b8565b50505050905090810190601f1680156101fd5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102136104ea565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561024f578181015183820152602001610237565b505050509050019250505060405180910390f35b61015b6004803603604081101561027957600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156102b157600080fd5b8201836020820111156102c357600080fd5b803590602001918460018302840111640100000000831117156102e557600080fd5b509092509050610559565b61015b6004803603604081101561030657600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561033e57600080fd5b82018360208201111561035057600080fd5b8035906020019184600183028401116401000000008311171561037257600080fd5b509092509050610613565b61015b6106d6565b6101656107d8565b61015b600480360360208110156103a357600080fd5b8101906020810181356401000000008111156103be57600080fd5b8201836020820111156103d057600080fd5b803590602001918460208302840111640100000000831117156103f257600080fd5b5090925090506107f4565b61015b6004803603602081101561041357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610b3e565b6104636004803603602081101561044657600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610b52565b604080519115158252519081900360200190f35b61047f610b7d565b61048a838383610c05565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60408051808201909152601981527f417574686f72697a6564466f7277617264657220312e302e3000000000000000602082015290565b6060600380548060200260200160405190810160405280929190818152602001828054801561054f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610524575b5050505050905090565b61056283610b3e565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405180806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039550909350505050a3505050565b61061b610d70565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561047f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e00000000604482015290519081900360640190fd5b60015473ffffffffffffffffffffffffffffffffffffffff16331461075c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015290519081900360640190fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b6107fc610de4565b61086757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b806108d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e6465720000000000604482015290519081900360640190fd5b60035460005b8181101561095b57600060026000600384815481106108f457fe5b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556001016108d9565b5060005b82811015610a8c576002600085858481811061097757fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168352508101919091526040016000205460ff1615610a1657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e6465727300604482015290519081900360640190fd5b600160026000868685818110610a2857fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff1683525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560010161095f565b50610a9960038484610f0c565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405180806020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252858582818152602001925060200280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b610b46610b7d565b610b4f81610e0b565b50565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b565b610c248373ffffffffffffffffffffffffffffffffffffffff16610f06565b610c8f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e7472616374000000000000604482015290519081900360640190fd5b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284376040519201945060009350909150508083038183865af19150503d8060008114610cfb576040519150601f19603f3d011682016040523d82523d6000602084013e610d00565b606091505b509150915081610d69578051610d61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180610faa6026913960400191505060405180910390fd5b805181602001fd5b5050505050565b610d7933610b52565b610c0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e6465720000000000000000000000604482015290519081900360640190fd5b600033610def6107d8565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610e9057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b3b151590565b828054828255906000526020600020908101928215610f84579160200282015b82811115610f845781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610f2c565b50610f90929150610f94565b5090565b5b80821115610f905760008155600101610f9556fe466f727761726465642063616c6c20726576657274656420776974686f757420726561736f6ea164736f6c6343000706000aa164736f6c6343000706000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AuthorizedForwarderCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OperatorCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"created\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deployNewForwarderAndTransferOwnership\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperatorAndForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b50604051615caf380380615caf83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615c016100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615c016000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613c8880620008d483390190565b611699806200455c83390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", } var OperatorFactoryABI = OperatorFactoryMetaData.ABI @@ -193,9 +193,9 @@ func (_OperatorFactory *OperatorFactoryCallerSession) Created(query common.Addre return _OperatorFactory.Contract.Created(&_OperatorFactory.CallOpts, query) } -func (_OperatorFactory *OperatorFactoryCaller) GetChainlinkToken(opts *bind.CallOpts) (common.Address, error) { +func (_OperatorFactory *OperatorFactoryCaller) LinkToken(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _OperatorFactory.contract.Call(opts, &out, "getChainlinkToken") + err := _OperatorFactory.contract.Call(opts, &out, "linkToken") if err != nil { return *new(common.Address), err @@ -207,12 +207,12 @@ func (_OperatorFactory *OperatorFactoryCaller) GetChainlinkToken(opts *bind.Call } -func (_OperatorFactory *OperatorFactorySession) GetChainlinkToken() (common.Address, error) { - return _OperatorFactory.Contract.GetChainlinkToken(&_OperatorFactory.CallOpts) +func (_OperatorFactory *OperatorFactorySession) LinkToken() (common.Address, error) { + return _OperatorFactory.Contract.LinkToken(&_OperatorFactory.CallOpts) } -func (_OperatorFactory *OperatorFactoryCallerSession) GetChainlinkToken() (common.Address, error) { - return _OperatorFactory.Contract.GetChainlinkToken(&_OperatorFactory.CallOpts) +func (_OperatorFactory *OperatorFactoryCallerSession) LinkToken() (common.Address, error) { + return _OperatorFactory.Contract.LinkToken(&_OperatorFactory.CallOpts) } func (_OperatorFactory *OperatorFactoryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { @@ -602,7 +602,7 @@ func (_OperatorFactory *OperatorFactory) Address() common.Address { type OperatorFactoryInterface interface { Created(opts *bind.CallOpts, query common.Address) (bool, error) - GetChainlinkToken(opts *bind.CallOpts) (common.Address, error) + LinkToken(opts *bind.CallOpts) (common.Address, error) TypeAndVersion(opts *bind.CallOpts) (string, error) diff --git a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go index 48c14a47820..69541858f31 100644 --- a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go +++ b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go @@ -31,8 +31,8 @@ var ( ) var OperatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CancelOracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"callbackAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cancelExpiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"acceptedContract\",\"type\":\"address\"}],\"name\":\"OwnableContractAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"TargetsUpdatedAuthorizedSenders\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"acceptAuthorizedReceivers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"}],\"name\":\"acceptOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequestByRequester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"distributeFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"data\",\"type\":\"bytes32\"}],\"name\":\"fulfillOracleRequest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"fulfillOracleRequest2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpiryTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"operatorRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"oracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerTransferAndCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSendersOn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003e8c38038062003e8c833981810160405260408110156200003c57600080fd5b508051602090910151808060006001600160a01b038216620000a5576040805162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000d857620000d881620000f2565b5050505060601b6001600160601b031916608052620001a3565b6001600160a01b03811633141562000151576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60805160601c613ca8620001e460003980610fde528061120a52806122c652806124d052806129c15280612e0352806131f252806136bb5250613ca86000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b14610c3c578063f3fef3a314610c7c578063fa00763a14610cc2578063fc4a03ed14610d0257610196565b8063a4c0ed3614610a8c578063eb007d9914610b61578063ee56997b14610bbf57610196565b806379ba5097116100bb57806379ba5097146109c35780638da5cb5b146109d8578063902fc370146109ed57610196565b80636ae0bc76146107cf5780636bd59ec0146108a35780636ee4d5531461096557610196565b80633c6d41b9116101435780634ab0d1901161011d5780634ab0d1901461065757806350188301146106eb5780635ffa62881461070057610196565b80633c6d41b9146104085780633ec5bc14146104e1578063404299461461057457610196565b8063181f5a7711610174578063181f5a77146102f25780632408afaa1461037c57806325cb5bc0146103e157610196565b806301994b991461019b578063033f49f71461021a578063165d35e1146102b4575b600080fd5b3480156101a757600080fd5b50610218600480360360208110156101be57600080fd5b8101906020810181356401000000008111156101d957600080fd5b8201836020820111156101eb57600080fd5b8035906020019184602083028401116401000000008311171561020d57600080fd5b509092509050610dd1565b005b34801561022657600080fd5b506102186004803603604081101561023d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516919081019060408101602082013564010000000081111561027557600080fd5b82018360208201111561028757600080fd5b803590602001918460018302840111640100000000831117156102a957600080fd5b509092509050610fd3565b3480156102c057600080fd5b506102c9611208565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156102fe57600080fd5b5061030761122c565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610341578181015183820152602001610329565b50505050905090810190601f16801561036e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561038857600080fd5b50610391611263565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156103cd5781810151838201526020016103b5565b505050509050019250505060405180910390f35b3480156103ed57600080fd5b506103f66112d2565b60408051918252519081900360200190f35b34801561041457600080fd5b50610218600480360360e081101561042b57600080fd5b73ffffffffffffffffffffffffffffffffffffffff823516916020810135916040820135917fffffffff000000000000000000000000000000000000000000000000000000006060820135169160808201359160a08101359181019060e0810160c08201356401000000008111156104a257600080fd5b8201836020820111156104b457600080fd5b803590602001918460018302840111640100000000831117156104d657600080fd5b5090925090506112d8565b3480156104ed57600080fd5b506102186004803603604081101561050457600080fd5b81019060208101813564010000000081111561051f57600080fd5b82018360208201111561053157600080fd5b8035906020019184602083028401116401000000008311171561055357600080fd5b91935091503573ffffffffffffffffffffffffffffffffffffffff1661149c565b34801561058057600080fd5b50610218600480360361010081101561059857600080fd5b73ffffffffffffffffffffffffffffffffffffffff8235811692602081013592604082013592606083013516917fffffffff000000000000000000000000000000000000000000000000000000006080820135169160a08201359160c081013591810190610100810160e082013564010000000081111561061857600080fd5b82018360208201111561062a57600080fd5b8035906020019184600183028401116401000000008311171561064c57600080fd5b5090925090506115ea565b34801561066357600080fd5b506106d7600480360360c081101561067a57600080fd5b5080359060208101359073ffffffffffffffffffffffffffffffffffffffff604082013516907fffffffff000000000000000000000000000000000000000000000000000000006060820135169060808101359060a001356117af565b604080519115158252519081900360200190f35b3480156106f757600080fd5b506103f6611ae8565b34801561070c57600080fd5b506102186004803603604081101561072357600080fd5b81019060208101813564010000000081111561073e57600080fd5b82018360208201111561075057600080fd5b8035906020019184602083028401116401000000008311171561077257600080fd5b91939092909160208101903564010000000081111561079057600080fd5b8201836020820111156107a257600080fd5b803590602001918460208302840111640100000000831117156107c457600080fd5b509092509050611af7565b3480156107db57600080fd5b506106d7600480360360c08110156107f257600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516917fffffffff00000000000000000000000000000000000000000000000000000000606082013516916080820135919081019060c0810160a082013564010000000081111561086457600080fd5b82018360208201111561087657600080fd5b8035906020019184600183028401116401000000008311171561089857600080fd5b509092509050611b80565b610218600480360360408110156108b957600080fd5b8101906020810181356401000000008111156108d457600080fd5b8201836020820111156108e657600080fd5b8035906020019184602083028401116401000000008311171561090857600080fd5b91939092909160208101903564010000000081111561092657600080fd5b82018360208201111561093857600080fd5b8035906020019184602083028401116401000000008311171561095a57600080fd5b509092509050611f85565b34801561097157600080fd5b506102186004803603608081101561098857600080fd5b508035906020810135907fffffffff00000000000000000000000000000000000000000000000000000000604082013516906060013561211c565b3480156109cf57600080fd5b50610218612341565b3480156109e457600080fd5b506102c9612447565b3480156109f957600080fd5b506106d760048036036060811015610a1057600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691602081013591810190606081016040820135640100000000811115610a4d57600080fd5b820183602082011115610a5f57600080fd5b80359060200191846001830284011164010000000083111715610a8157600080fd5b509092509050612463565b348015610a9857600080fd5b5061021860048036036060811015610aaf57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691602081013591810190606081016040820135640100000000811115610aec57600080fd5b820183602082011115610afe57600080fd5b80359060200191846001830284011164010000000083111715610b2057600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506125c9945050505050565b348015610b6d57600080fd5b5061021860048036036080811015610b8457600080fd5b508035906020810135907fffffffff0000000000000000000000000000000000000000000000000000000060408201351690606001356127cb565b348015610bcb57600080fd5b5061021860048036036020811015610be257600080fd5b810190602081018135640100000000811115610bfd57600080fd5b820183602082011115610c0f57600080fd5b80359060200191846020830284011164010000000083111715610c3157600080fd5b509092509050612a3d565b348015610c4857600080fd5b5061021860048036036020811015610c5f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612d84565b348015610c8857600080fd5b5061021860048036036040811015610c9f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612d98565b348015610cce57600080fd5b506106d760048036036020811015610ce557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612ec4565b348015610d0e57600080fd5b5061021860048036036040811015610d2557600080fd5b810190602081018135640100000000811115610d4057600080fd5b820183602082011115610d5257600080fd5b80359060200191846020830284011164010000000083111715610d7457600080fd5b919390929091602081019035640100000000811115610d9257600080fd5b820183602082011115610da457600080fd5b80359060200191846020830284011164010000000083111715610dc657600080fd5b509092509050612eef565b610dd9613128565b610e4457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b60005b81811015610fce57600160056000858585818110610e6157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550828282818110610edb57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a2828282818110610f4657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610faa57600080fd5b505af1158015610fbe573d6000803e3d6000fd5b505060019092019150610e479050565b505050565b610fdb61315e565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561109757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b00000000000000000000000000604482015290519081900360640190fd5b6110b68473ffffffffffffffffffffffffffffffffffffffff166131e6565b61112157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e7472616374000000000000604482015290519081900360640190fd5b60008473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284376040519201945060009350909150508083038183865af19150503d806000811461118c576040519150601f19603f3d011682016040523d82523d6000602084013e611191565b606091505b505090508061120157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c65640000000000000000000000604482015290519081900360640190fd5b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000090565b60408051808201909152600e81527f4f70657261746f7220312e302e30000000000000000000000000000000000000602082015290565b606060018054806020026020016040519081016040528092919081815260200182805480156112c857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161129d575b5050505050905090565b61012c81565b6112e0611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461137957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b60008061138a8a8a8c8a8a8a6131ec565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051808a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001858152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039c50909a5050505050505050505050a250505050505050505050565b6114a461315e565b60005b828110156115e4576000600560008686858181106114c157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555083838281811061153b57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f2fde38b836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050600060405180830381600087803b1580156115c057600080fd5b505af11580156115d4573d6000803e3d6000fd5b5050600190920191506114a79050565b50505050565b6115f2611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461168b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b60008061169c8b8b8a8a8a8a6131ec565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051808a73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018881526020018773ffffffffffffffffffffffffffffffffffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001858152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018290039c50909a5050505050505050505050a25050505050505050505050565b60006117b9613498565b600087815260046020526040902054879060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001661185a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c6964207265717565737449640000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff16156118f157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e7472616374000000000000604482015290519081900360640190fd5b6119008989898989600161350c565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a101561199d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f75676820676173604482015290519081900360640190fd5b60408051602481018b9052604480820187905282518083039091018152606490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000008a161781529151815160009373ffffffffffffffffffffffffffffffffffffffff8c169392918291908083835b60208310611a7057805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611a33565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ad2576040519150601f19603f3d011682016040523d82523d6000602084013e611ad7565b606091505b50909b9a5050505050505050505050565b6000611af261369a565b905090565b611aff613128565b611b6a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b611b748484610dd1565b6115e484848484612eef565b6000611b8a613498565b600088815260046020526040902054889060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016611c2b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c6964207265717565737449640000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611cc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e7472616374000000000000604482015290519081900360640190fd5b8985856020811015611d3557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e2033322062797465730000000000604482015290519081900360640190fd5b8135838114611da557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d7573742062652072657175657374496400000000604482015290519081900360640190fd5b611db48e8e8e8e8e600261350c565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611e5157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f75676820676173604482015290519081900360640190fd5b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b60405160200180847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526004018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310611f0757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611eca565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611f69576040519150601f19603f3d011682016040523d82523d6000602084013e611f6e565b606091505b509098505050505050505050979650505050505050565b8215801590611f9357508281145b611ffe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e677468287329000000000000000000604482015290519081900360640190fd5b3460005b848110156120ae57600084848381811061201857fe5b905060200201359050612034818461377890919063ffffffff16565b925086868381811061204257fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156120a4573d6000803e3d6000fd5b5050600101612002565b50801561120157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e74000000000000000000000000000000604482015290519081900360640190fd5b600061212a843385856137ef565b60008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146121d257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b4282111561224157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f74206578706972656400000000000000000000604482015290519081900360640190fd5b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815233600482015260248101869052905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b15801561230e57600080fd5b505af1158015612322573d6000803e3d6000fd5b505050506040513d602081101561233857600080fd5b50505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146123c757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015290519081900360640190fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60025473ffffffffffffffffffffffffffffffffffffffff1690565b600061246d61315e565b838061247761369a565b10156124ce576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613c676035913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0878787876040518563ffffffff1660e01b8152600401808573ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050602060405180830381600087803b15801561259357600080fd5b505af11580156125a7573d6000803e3d6000fd5b505050506040513d60208110156125bd57600080fd5b50519695505050505050565b6125d1611208565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461266a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e00000000000000000000000000604482015290519081900360640190fd5b6020810151819061267b8183613874565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff16846040518082805190602001908083835b602083106126ee57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016126b1565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811461274e576040519150601f19603f3d011682016040523d82523d6000602084013e612753565b606091505b50509050806127c357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f2063726561746520726571756573740000000000000000604482015290519081900360640190fd5b505050505050565b60003385604051602001808373ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001925050506040516020818303038152906040528051906020012090506000612825853386866137ef565b60008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146128cd57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b4283111561293c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f74206578706972656400000000000000000000604482015290519081900360640190fd5b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a2604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815233600482015260248101879052905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163a9059cbb9160448083019260209291908290030181600087803b158015612a0957600080fd5b505af1158015612a1d573d6000803e3d6000fd5b505050506040513d6020811015612a3357600080fd5b5050505050505050565b612a45613128565b612ab057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b80612b1c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e6465720000000000604482015290519081900360640190fd5b60015460005b81811015612ba357600080600060018481548110612b3c57fe5b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101612b22565b5060005b82811015612cd257600080858584818110612bbe57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168352508101919091526040016000205460ff1615612c5d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e6465727300604482015290519081900360640190fd5b6001600080868685818110612c6e57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff1683525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101612ba7565b50612cdf60018484613bd2565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a083833360405180806020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281038252858582818152602001925060200280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a1505050565b612d8c61315e565b612d95816139e5565b50565b612da061315e565b8080612daa61369a565b1015612e01576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526035815260200180613c676035913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612e9257600080fd5b505af1158015612ea6573d6000803e3d6000fd5b505050506040513d6020811015612ebc57600080fd5b5051610fce57fe5b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b612ef7613128565b612f6257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e64657273000000604482015290519081900360640190fd5b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040518080602001806020018473ffffffffffffffffffffffffffffffffffffffff1681526020018381038352888882818152602001925060200280828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169091018481038352868152602090810191508790870280828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003995090975050505050505050a160005b838110156112015784848281811061306657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040180806020018281038252848482818152602001925060200280828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b15801561310457600080fd5b505af1158015613118573d6000803e3d6000fd5b5050600190920191506130529050565b600061313333612ec4565b80611af2575033613142612447565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146131e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015290519081900360640190fd5b565b3b151590565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156132ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b00000000000000000000000000604482015290519081900360640190fd5b6040805160608b901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083019190915260348083018990528351808403909101815260549092018352815191810191909120600081815260049092529190205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016156133a357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e69717565204944000000000000000000000000604482015290519081900360640190fd5b6133af4261012c613ae1565b915060006133bf898989866137ef565b905060405180604001604052808260ff191681526020016133df87613b5c565b60ff90811690915260008681526004602090815260409091208351815494909201519092167f01000000000000000000000000000000000000000000000000000000000000000260089190911c7fff00000000000000000000000000000000000000000000000000000000000000909316929092177effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919091179055600654613488908a613ae1565b6006555050965096945050505050565b6134a133612ec4565b6131e457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e6465720000000000000000000000604482015290519081900360640190fd5b600061351a868686866137ef565b60008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146135c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d6174636820726571756573742049440000604482015290519081900360640190fd5b6135cb82613b5c565b60008881526004602052604090205460ff9182167f0100000000000000000000000000000000000000000000000000000000000000909104909116111561367357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d617463680000000000000000604482015290519081900360640190fd5b6006546136809087613778565b600655505050600093845250506004602052506040812055565b6000806136b3600160065461377890919063ffffffff16565b9050613772817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561374057600080fd5b505afa158015613754573d6000803e3d6000fd5b505050506040513d602081101561376a57600080fd5b505190613778565b91505090565b6000828211156137e957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6040805160208082019690965260609490941b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016848201527fffffffff000000000000000000000000000000000000000000000000000000009290921660548401526058808401919091528151808403909101815260789092019052805191012090565b8051604411156138e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e67746800000000000000000000604482015290519081900360640190fd5b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b900000000000000000000000000000000000000000000000000000000148061397657507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b6139e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e730000604482015290519081900360640190fd5b5050565b73ffffffffffffffffffffffffffffffffffffffff8116331415613a6a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015290519081900360640190fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600082820183811015613b5557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60006101008210613bce57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e756d62657220746f6f2062696720746f206361737400000000000000000000604482015290519081900360640190fd5b5090565b828054828255906000526020600020908101928215613c4a579160200282015b82811115613c4a5781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190613bf2565b50613bce9291505b80821115613bce5760008155600101613c5256fe416d6f756e74207265717565737465642069732067726561746572207468616e20776974686472617761626c652062616c616e6365a164736f6c6343000706000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CancelOracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"callbackAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cancelExpiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"acceptedContract\",\"type\":\"address\"}],\"name\":\"OwnableContractAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"TargetsUpdatedAuthorizedSenders\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EXPIRYTIME\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"acceptAuthorizedReceivers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"}],\"name\":\"acceptOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequestByRequester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"distributeFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"data\",\"type\":\"bytes32\"}],\"name\":\"fulfillOracleRequest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"fulfillOracleRequest2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"operatorRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"oracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerTransferAndCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSendersOn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a", } var OperatorABI = OperatorMetaData.ABI @@ -171,6 +171,28 @@ func (_Operator *OperatorTransactorRaw) Transact(opts *bind.TransactOpts, method return _Operator.Contract.contract.Transact(opts, method, params...) } +func (_Operator *OperatorCaller) EXPIRYTIME(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Operator.contract.Call(opts, &out, "EXPIRYTIME") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_Operator *OperatorSession) EXPIRYTIME() (*big.Int, error) { + return _Operator.Contract.EXPIRYTIME(&_Operator.CallOpts) +} + +func (_Operator *OperatorCallerSession) EXPIRYTIME() (*big.Int, error) { + return _Operator.Contract.EXPIRYTIME(&_Operator.CallOpts) +} + func (_Operator *OperatorCaller) GetAuthorizedSenders(opts *bind.CallOpts) ([]common.Address, error) { var out []interface{} err := _Operator.contract.Call(opts, &out, "getAuthorizedSenders") @@ -215,28 +237,6 @@ func (_Operator *OperatorCallerSession) GetChainlinkToken() (common.Address, err return _Operator.Contract.GetChainlinkToken(&_Operator.CallOpts) } -func (_Operator *OperatorCaller) GetExpiryTime(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Operator.contract.Call(opts, &out, "getExpiryTime") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_Operator *OperatorSession) GetExpiryTime() (*big.Int, error) { - return _Operator.Contract.GetExpiryTime(&_Operator.CallOpts) -} - -func (_Operator *OperatorCallerSession) GetExpiryTime() (*big.Int, error) { - return _Operator.Contract.GetExpiryTime(&_Operator.CallOpts) -} - func (_Operator *OperatorCaller) IsAuthorizedSender(opts *bind.CallOpts, sender common.Address) (bool, error) { var out []interface{} err := _Operator.contract.Call(opts, &out, "isAuthorizedSender", sender) @@ -1627,12 +1627,12 @@ func (_Operator *Operator) Address() common.Address { } type OperatorInterface interface { + EXPIRYTIME(opts *bind.CallOpts) (*big.Int, error) + GetAuthorizedSenders(opts *bind.CallOpts) ([]common.Address, error) GetChainlinkToken(opts *bind.CallOpts) (common.Address, error) - GetExpiryTime(opts *bind.CallOpts) (*big.Int, error) - IsAuthorizedSender(opts *bind.CallOpts, sender common.Address) (bool, error) Owner(opts *bind.CallOpts) (common.Address, error) diff --git a/integration-tests/contracts/ethereum/PerformDataChecker.go b/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go similarity index 70% rename from integration-tests/contracts/ethereum/PerformDataChecker.go rename to core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go index 99c8d1380cd..aa639deb9c0 100644 --- a/integration-tests/contracts/ethereum/PerformDataChecker.go +++ b/core/gethwrappers/generated/perform_data_checker_wrapper/perform_data_checker_wrapper.go @@ -1,14 +1,14 @@ -package ethereum - // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. +package perform_data_checker_wrapper + import ( "errors" "math/big" "strings" - "github.com/ethereum/go-ethereum" + ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -25,11 +25,12 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription + _ = abi.ConvertType ) var PerformDataCheckerMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"expectedData\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_expectedData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"expectedData\",\"type\":\"bytes\"}],\"name\":\"setExpectedData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506040516107d33803806107d383398101604081905261002f916100e2565b8051610042906001906020840190610049565b5050610202565b828054610055906101b1565b90600052602060002090601f01602090048101928261007757600085556100bd565b82601f1061009057805160ff19168380011785556100bd565b828001600101855582156100bd579182015b828111156100bd5782518255916020019190600101906100a2565b506100c99291506100cd565b5090565b5b808211156100c957600081556001016100ce565b600060208083850312156100f557600080fd5b82516001600160401b038082111561010c57600080fd5b818501915085601f83011261012057600080fd5b815181811115610132576101326101ec565b604051601f8201601f19908116603f0116810190838211818310171561015a5761015a6101ec565b81604052828152888684870101111561017257600080fd5b600093505b828410156101945784840186015181850187015292850192610177565b828411156101a55760008684830101525b98975050505050505050565b600181811c908216806101c557607f821691505b602082108114156101e657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052604160045260246000fd5b6105c2806102116000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806361bc221a1161005057806361bc221a146100945780636e04ff0d146100b05780638d1a93c2146100d157600080fd5b80632aa0f7951461006c5780634585e33b14610081575b600080fd5b61007f61007a366004610304565b6100e6565b005b61007f61008f366004610304565b6100f7565b61009d60005481565b6040519081526020015b60405180910390f35b6100c36100be366004610304565b610145565b6040516100a79291906104c4565b6100d96101bf565b6040516100a791906104e7565b6100f26001838361024d565b505050565b600160405161010691906103f1565b6040518091039020828260405161011e9291906103e1565b604051809103902014156101415760008054908061013b83610555565b91905055505b5050565b60006060600160405161015891906103f1565b604051809103902084846040516101709291906103e1565b604051809103902014848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b600180546101cc90610501565b80601f01602080910402602001604051908101604052809291908181526020018280546101f890610501565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b505050505081565b82805461025990610501565b90600052602060002090601f01602090048101928261027b57600085556102df565b82601f106102b2578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008235161785556102df565b828001600101855582156102df579182015b828111156102df5782358255916020019190600101906102c4565b506102eb9291506102ef565b5090565b5b808211156102eb57600081556001016102f0565b6000806020838503121561031757600080fd5b823567ffffffffffffffff8082111561032f57600080fd5b818501915085601f83011261034357600080fd5b81358181111561035257600080fd5b86602082850101111561036457600080fd5b60209290920196919550909350505050565b6000815180845260005b8181101561039c57602081850181015186830182015201610380565b818111156103ae576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8183823760009101908152919050565b600080835481600182811c91508083168061040d57607f831692505b6020808410821415610446577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b81801561045a5760018114610489576104b6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008616895284890196506104b6565b60008a81526020902060005b868110156104ae5781548b820152908501908301610495565b505084890196505b509498975050505050505050565b82151581526040602082015260006104df6040830184610376565b949350505050565b6020815260006104fa6020830184610376565b9392505050565b600181811c9082168061051557607f821691505b6020821081141561054f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156105ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b506040516108d33803806108d383398101604081905261002f91610058565b600161003b82826101aa565b5050610269565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561006b57600080fd5b82516001600160401b038082111561008257600080fd5b818501915085601f83011261009657600080fd5b8151818111156100a8576100a8610042565b604051601f8201601f19908116603f011681019083821181831017156100d0576100d0610042565b8160405282815288868487010111156100e857600080fd5b600093505b8284101561010a57848401860151818501870152928501926100ed565b600086848301015280965050505050505092915050565b600181811c9082168061013557607f821691505b60208210810361015557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156101a557600081815260208120601f850160051c810160208610156101825750805b601f850160051c820191505b818110156101a15782815560010161018e565b5050505b505050565b81516001600160401b038111156101c3576101c3610042565b6101d7816101d18454610121565b8461015b565b602080601f83116001811461020c57600084156101f45750858301515b600019600386901b1c1916600185901b1785556101a1565b600085815260208120601f198616915b8281101561023b5788860151825594840194600190910190840161021c565b50858210156102595787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61065b806102786000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806361bc221a1161005057806361bc221a146100945780636e04ff0d146100b05780638d1a93c2146100d157600080fd5b80632aa0f7951461006c5780634585e33b14610081575b600080fd5b61007f61007a36600461024d565b6100e6565b005b61007f61008f36600461024d565b6100f8565b61009d60005481565b6040519081526020015b60405180910390f35b6100c36100be36600461024d565b610145565b6040516100a7929190610323565b6100d96101bf565b6040516100a79190610346565b60016100f3828483610430565b505050565b6001604051610107919061054b565b6040518091039020828260405161011f9291906105df565b6040518091039020036101415760008054908061013b836105ef565b91905055505b5050565b600060606001604051610158919061054b565b604051809103902084846040516101709291906105df565b604051809103902014848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b600180546101cc9061038f565b80601f01602080910402602001604051908101604052809291908181526020018280546101f89061038f565b80156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b505050505081565b6000806020838503121561026057600080fd5b823567ffffffffffffffff8082111561027857600080fd5b818501915085601f83011261028c57600080fd5b81358181111561029b57600080fd5b8660208285010111156102ad57600080fd5b60209290920196919550909350505050565b6000815180845260005b818110156102e5576020818501810151868301820152016102c9565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b821515815260406020820152600061033e60408301846102bf565b949350505050565b60208152600061035960208301846102bf565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600181811c908216806103a357607f821691505b6020821081036103dc577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156100f357600081815260208120601f850160051c810160208610156104095750805b601f850160051c820191505b8181101561042857828155600101610415565b505050505050565b67ffffffffffffffff83111561044857610448610360565b61045c83610456835461038f565b836103e2565b6000601f8411600181146104ae57600085156104785750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610544565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156104fd57868501358255602094850194600190920191016104dd565b5086821015610538577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60008083546105598161038f565b6001828116801561057157600181146105a4576105d3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506105d3565b8760005260208060002060005b858110156105ca5781548a8201529084019082016105b1565b50505082870194505b50929695505050505050565b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610647577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c6343000810000a", } var PerformDataCheckerABI = PerformDataCheckerMetaData.ABI @@ -137,11 +138,11 @@ func NewPerformDataCheckerFilterer(address common.Address, filterer bind.Contrac } func bindPerformDataChecker(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(PerformDataCheckerABI)) + parsed, err := PerformDataCheckerMetaData.GetAbi() if err != nil { return nil, err } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } func (_PerformDataChecker *PerformDataCheckerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { diff --git a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go index 27f7c4ebbb5..43ae1a3f5b4 100644 --- a/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go +++ b/core/gethwrappers/generated/trusted_blockhash_store/trusted_blockhash_store.go @@ -32,7 +32,7 @@ var ( var TrustedBlockhashStoreMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidRecentBlockhash\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrustedBlockhashes\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInWhitelist\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"getBlockhash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_whitelist\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_whitelistStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"whitelist\",\"type\":\"address[]\"}],\"name\":\"setWhitelist\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"store\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"storeEarliest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"blockNums\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"blockhashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"recentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"recentBlockhash\",\"type\":\"bytes32\"}],\"name\":\"storeTrusted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"header\",\"type\":\"bytes\"}],\"name\":\"storeVerifyHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620014e8380380620014e88339810160408190526200003491620003e8565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018560201b60201c565b5062000517565b6001600160a01b038116331415620001345760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018f620002ec565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001ca575b5050855193945062000207936004935060208701925090506200034a565b5060005b81518110156200027757600060036000848481518110620002305762000230620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026e81620004c1565b9150506200020b565b5060005b8251811015620002e757600160036000858481518110620002a057620002a0620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002de81620004c1565b9150506200027b565b505050565b6000546001600160a01b03163314620003485760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a2579160200282015b82811115620003a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036b565b50620003b0929150620003b4565b5090565b5b80821115620003b05760008155600101620003b5565b80516001600160a01b0381168114620003e357600080fd5b919050565b60006020808385031215620003fc57600080fd5b82516001600160401b03808211156200041457600080fd5b818501915085601f8301126200042957600080fd5b8151818111156200043e576200043e62000501565b8060051b604051601f19603f8301168101818110858211171562000466576200046662000501565b604052828152858101935084860182860187018a10156200048657600080fd5b600095505b83861015620004b4576200049f81620003cb565b8552600195909501949386019386016200048b565b5098975050505050505050565b6000600019821415620004e457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610fc180620005276000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610d03565b6101ee565b005b6100f66100f1366004610d9a565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610d9a565b61035d565b6100e16103e8565b6100e16104e5565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610d9a565b6104ff565b604051908152602001610117565b6101a5610190366004610c34565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610c34565b61057b565b6100e16101d6366004610c4f565b61058f565b6100e16101e9366004610db3565b610745565b60006101f9836107e8565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610f56565b90506020020135600260008a8a858181106102f0576102f0610f56565b90506020020135815260200190815260200160002081905550808061031490610eee565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107e8565b9050806103d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610469576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cd565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104fd6101006104f3610903565b61012e9190610ed7565b565b60008181526002602052604081205480610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103cd565b92915050565b6105836109a9565b61058c81610a2a565b50565b6105976109a9565b600060048054806020026020016040519081016040528092919081815260200182805480156105fc57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d1575b5050855193945061061893600493506020870192509050610b20565b5060005b81518110156106ac5760006003600084848151811061063d5761063d610f56565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106a481610eee565b91505061061c565b5060005b8251811015610740576001600360008584815181106106d1576106d1610f56565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073881610eee565b9150506106b0565b505050565b60026000610754846001610ebf565b8152602001908152602001600020548180519060200120146107d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103cd565b6024015160009182526002602052604090912055565b60004661a4b18114806107fd575062066eed81145b8061080a575062066eee81145b156108f3576101008367ffffffffffffffff16610825610903565b61082f9190610ed7565b118061084c575061083e610903565b8367ffffffffffffffff1610155b1561085a5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b1580156108b457600080fd5b505afa1580156108c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ec9190610d81565b9392505050565b505067ffffffffffffffff164090565b60004661a4b1811480610918575062066eed81145b156109a257606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096457600080fd5b505afa158015610978573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099c9190610d81565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cd565b73ffffffffffffffffffffffffffffffffffffffff8116331415610aaa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cd565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610b9a579160200282015b82811115610b9a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b40565b50610ba6929150610baa565b5090565b5b80821115610ba65760008155600101610bab565b803573ffffffffffffffffffffffffffffffffffffffff81168114610be357600080fd5b919050565b60008083601f840112610bfa57600080fd5b50813567ffffffffffffffff811115610c1257600080fd5b6020830191508360208260051b8501011115610c2d57600080fd5b9250929050565b600060208284031215610c4657600080fd5b6108ec82610bbf565b60006020808385031215610c6257600080fd5b823567ffffffffffffffff80821115610c7a57600080fd5b818501915085601f830112610c8e57600080fd5b813581811115610ca057610ca0610f85565b8060051b9150610cb1848301610e70565b8181528481019084860184860187018a1015610ccc57600080fd5b600095505b83861015610cf657610ce281610bbf565b835260019590950194918601918601610cd1565b5098975050505050505050565b60008060008060008060808789031215610d1c57600080fd5b863567ffffffffffffffff80821115610d3457600080fd5b610d408a838b01610be8565b90985096506020890135915080821115610d5957600080fd5b50610d6689828a01610be8565b979a9699509760408101359660609091013595509350505050565b600060208284031215610d9357600080fd5b5051919050565b600060208284031215610dac57600080fd5b5035919050565b60008060408385031215610dc657600080fd5b8235915060208084013567ffffffffffffffff80821115610de657600080fd5b818601915086601f830112610dfa57600080fd5b813581811115610e0c57610e0c610f85565b610e3c847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610e70565b91508082528784828501011115610e5257600080fd5b80848401858401376000848284010152508093505050509250929050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610eb757610eb7610f85565b604052919050565b60008219821115610ed257610ed2610f27565b500190565b600082821015610ee957610ee9610f27565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f2057610f20610f27565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b50604051620014ec380380620014ec8339810160408190526200003491620003e8565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018560201b60201c565b5062000517565b6001600160a01b038116331415620001345760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018f620002ec565b60006004805480602002602001604051908101604052809291908181526020018280548015620001e957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311620001ca575b5050855193945062000207936004935060208701925090506200034a565b5060005b81518110156200027757600060036000848481518110620002305762000230620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff1916911515919091179055806200026e81620004c1565b9150506200020b565b5060005b8251811015620002e757600160036000858481518110620002a057620002a0620004eb565b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff191691151591909117905580620002de81620004c1565b9150506200027b565b505050565b6000546001600160a01b03163314620003485760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b828054828255906000526020600020908101928215620003a2579160200282015b82811115620003a257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200036b565b50620003b0929150620003b4565b5090565b5b80821115620003b05760008155600101620003b5565b80516001600160a01b0381168114620003e357600080fd5b919050565b60006020808385031215620003fc57600080fd5b82516001600160401b03808211156200041457600080fd5b818501915085601f8301126200042957600080fd5b8151818111156200043e576200043e62000501565b8060051b604051601f19603f8301168101818110858211171562000466576200046662000501565b604052828152858101935084860182860187018a10156200048657600080fd5b600095505b83861015620004b4576200049f81620003cb565b8552600195909501949386019386016200048b565b5098975050505050505050565b6000600019821415620004e457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610fc580620005276000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80638da5cb5b11610081578063f2fde38b1161005b578063f2fde38b146101b5578063f4217648146101c8578063fadff0e1146101db57600080fd5b80638da5cb5b14610143578063e9413d3814610161578063e9ecc1541461018257600080fd5b80636057361d116100b25780636057361d1461012057806379ba50971461013357806383b6d6b71461013b57600080fd5b80633b69ad60146100ce5780635c7de309146100e3575b600080fd5b6100e16100dc366004610d07565b6101ee565b005b6100f66100f1366004610d9e565b610326565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100e161012e366004610d9e565b61035d565b6100e16103e8565b6100e16104e5565b60005473ffffffffffffffffffffffffffffffffffffffff166100f6565b61017461016f366004610d9e565b6104ff565b604051908152602001610117565b6101a5610190366004610c38565b60036020526000908152604090205460ff1681565b6040519015158152602001610117565b6100e16101c3366004610c38565b61057b565b6100e16101d6366004610c53565b61058f565b6100e16101e9366004610db7565b610745565b60006101f9836107e8565b9050818114610234576040517fd2f69c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526003602052604090205460ff1661027d576040517f5b0aa2ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8584146102b6576040517fbd75093300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8681101561031c578585828181106102d3576102d3610f5a565b90506020020135600260008a8a858181106102f0576102f0610f5a565b90506020020135815260200190815260200160002081905550808061031490610ef2565b9150506102b9565b5050505050505050565b6004818154811061033657600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6000610368826107e8565b9050806103d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f626c6f636b68617368286e29206661696c65640000000000000000000000000060448201526064015b60405180910390fd5b60009182526002602052604090912055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610469576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cd565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104fd6101006104f36108ed565b61012e9190610edb565b565b60008181526002602052604081205480610575576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f72650000000060448201526064016103cd565b92915050565b61058361098a565b61058c81610a0b565b50565b61059761098a565b600060048054806020026020016040519081016040528092919081815260200182805480156105fc57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116105d1575b5050855193945061061893600493506020870192509050610b24565b5060005b81518110156106ac5760006003600084848151811061063d5761063d610f5a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055806106a481610ef2565b91505061061c565b5060005b8251811015610740576001600360008584815181106106d1576106d1610f5a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558061073881610ef2565b9150506106b0565b505050565b60026000610754846001610ec3565b8152602001908152602001600020548180519060200120146107d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b686173680000000060448201526064016103cd565b6024015160009182526002602052604090912055565b6000466107f481610b01565b156108dd576101008367ffffffffffffffff1661080f6108ed565b6108199190610edb565b118061083657506108286108ed565b8367ffffffffffffffff1610155b156108445750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b15801561089e57600080fd5b505afa1580156108b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d69190610d85565b9392505050565b505067ffffffffffffffff164090565b6000466108f981610b01565b1561098357606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561094557600080fd5b505afa158015610959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097d9190610d85565b91505090565b4391505090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cd565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a8b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cd565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610b15575062066eed82145b8061057557505062066eee1490565b828054828255906000526020600020908101928215610b9e579160200282015b82811115610b9e57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b44565b50610baa929150610bae565b5090565b5b80821115610baa5760008155600101610baf565b803573ffffffffffffffffffffffffffffffffffffffff81168114610be757600080fd5b919050565b60008083601f840112610bfe57600080fd5b50813567ffffffffffffffff811115610c1657600080fd5b6020830191508360208260051b8501011115610c3157600080fd5b9250929050565b600060208284031215610c4a57600080fd5b6108d682610bc3565b60006020808385031215610c6657600080fd5b823567ffffffffffffffff80821115610c7e57600080fd5b818501915085601f830112610c9257600080fd5b813581811115610ca457610ca4610f89565b8060051b9150610cb5848301610e74565b8181528481019084860184860187018a1015610cd057600080fd5b600095505b83861015610cfa57610ce681610bc3565b835260019590950194918601918601610cd5565b5098975050505050505050565b60008060008060008060808789031215610d2057600080fd5b863567ffffffffffffffff80821115610d3857600080fd5b610d448a838b01610bec565b90985096506020890135915080821115610d5d57600080fd5b50610d6a89828a01610bec565b979a9699509760408101359660609091013595509350505050565b600060208284031215610d9757600080fd5b5051919050565b600060208284031215610db057600080fd5b5035919050565b60008060408385031215610dca57600080fd5b8235915060208084013567ffffffffffffffff80821115610dea57600080fd5b818601915086601f830112610dfe57600080fd5b813581811115610e1057610e10610f89565b610e40847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610e74565b91508082528784828501011115610e5657600080fd5b80848401858401376000848284010152508093505050509250929050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610ebb57610ebb610f89565b604052919050565b60008219821115610ed657610ed6610f2b565b500190565b600082821015610eed57610eed610f2b565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f2457610f24610f2b565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var TrustedBlockhashStoreABI = TrustedBlockhashStoreMetaData.ABI diff --git a/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go b/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go index 4276610f731..4f9fe79d77c 100644 --- a/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go +++ b/core/gethwrappers/generated/upkeep_counter_wrapper/upkeep_counter_wrapper.go @@ -32,7 +32,7 @@ var ( var UpkeepCounterMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setSpread\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5060405161044d38038061044d8339818101604052604081101561003357600080fd5b508051602090910151600091825560015560038190554360025560048190556005556103e9806100646000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80637f407edf11610076578063917d895f1161005b578063917d895f1461027b578063947a36fb14610283578063d832d92f1461028b576100be565b80637f407edf14610250578063806b984f14610273576100be565b806361bc221a116100a757806361bc221a1461014f5780636250a13a146101575780636e04ff0d1461015f576100be565b80632cb15864146100c35780634585e33b146100dd575b600080fd5b6100cb6102a7565b60408051918252519081900360200190f35b61014d600480360360208110156100f357600080fd5b81019060208101813564010000000081111561010e57600080fd5b82018360208201111561012057600080fd5b8035906020019184600183028401116401000000008311171561014257600080fd5b5090925090506102ad565b005b6100cb610324565b6100cb61032a565b6101cf6004803603602081101561017557600080fd5b81019060208101813564010000000081111561019057600080fd5b8201836020820111156101a257600080fd5b803590602001918460018302840111640100000000831117156101c457600080fd5b509092509050610330565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156102145781810151838201526020016101fc565b50505050905090810190601f1680156102415780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b61014d6004803603604081101561026657600080fd5b5080359060200135610382565b6100cb610394565b6100cb61039a565b6100cb6103a0565b6102936103a6565b604080519115158252519081900360200190f35b60045481565b6004546102b957436004555b4360028190556005805460010190819055600454600354604080519283526020830194909452818401526060810191909152905132917f8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa919081900360800190a25050600254600355565b60055481565b60005481565b6000606061033c6103a6565b848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b60009182556001556004819055600555565b60025481565b60035481565b60015481565b6000600454600014156103bb575060016103d9565b60005460045443031080156103d65750600154600254430310155b90505b9056fea164736f6c6343000706000a", + Bin: "0x608060405234801561001057600080fd5b5060405161048338038061048383398101604081905261002f9161004d565b60009182556001556003819055436002556004819055600555610071565b6000806040838503121561006057600080fd5b505080516020909101519092909150565b610403806100806000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80637f407edf11610076578063917d895f1161005b578063917d895f14610150578063947a36fb14610159578063d832d92f1461016257600080fd5b80637f407edf14610127578063806b984f1461014757600080fd5b806361bc221a116100a757806361bc221a146100f45780636250a13a146100fd5780636e04ff0d1461010657600080fd5b80632cb15864146100c35780634585e33b146100df575b600080fd5b6100cc60045481565b6040519081526020015b60405180910390f35b6100f26100ed366004610291565b61017a565b005b6100cc60055481565b6100cc60005481565b610119610114366004610291565b6101fd565b6040516100d6929190610303565b6100f2610135366004610379565b60009182556001556004819055600555565b6100cc60025481565b6100cc60035481565b6100cc60015481565b61016a61024f565b60405190151581526020016100d6565b60045460000361018957436004555b4360025560055461019b9060016103ca565b600581905560045460025460035460408051938452602084019290925290820152606081019190915232907f8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa9060800160405180910390a25050600254600355565b6000606061020961024f565b848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b60006004546000036102615750600190565b60005460045461027190436103e3565b10801561028c575060015460025461028990436103e3565b10155b905090565b600080602083850312156102a457600080fd5b823567ffffffffffffffff808211156102bc57600080fd5b818501915085601f8301126102d057600080fd5b8135818111156102df57600080fd5b8660208285010111156102f157600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b818110156103395785810183015185820160600152820161031d565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b6000806040838503121561038c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103dd576103dd61039b565b92915050565b818103818111156103dd576103dd61039b56fea164736f6c6343000810000a", } var UpkeepCounterABI = UpkeepCounterMetaData.ABI diff --git a/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go b/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go index 6212853de68..e6770fd074f 100644 --- a/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go +++ b/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper/upkeep_perform_counter_restrictive_wrapper.go @@ -32,7 +32,7 @@ var ( var UpkeepPerformCounterRestrictiveMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_averageEligibilityCadence\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"eligible\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialCall\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nextEligible\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"averageEligibilityCadence\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkEligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCountPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialCall\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextEligible\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setCheckGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newTestRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_newAverageEligibilityCadence\",\"type\":\"uint256\"}],\"name\":\"setSpread\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6080604052600080556000600155600060075534801561001e57600080fd5b506040516106883803806106888339818101604052604081101561004157600080fd5b508051602090910151600291909155600355610626806100626000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80637145f11b11610097578063b30566b411610066578063b30566b414610325578063c228a98e1461032d578063d826f88f14610335578063e303666f1461033d576100f5565b80637145f11b146102c15780637f407edf146102f2578063926f086e14610315578063a9a4c57c1461031d576100f5565b80634585e33b116100d35780634585e33b14610150578063523d9b8a146101c05780636250a13a146101c85780636e04ff0d146101d0576100f5565b806313bda75b146100fa5780632555d2cf146101195780632ff3617d14610136575b600080fd5b6101176004803603602081101561011057600080fd5b5035610345565b005b6101176004803603602081101561012f57600080fd5b503561034a565b61013e61034f565b60408051918252519081900360200190f35b6101176004803603602081101561016657600080fd5b81019060208101813564010000000081111561018157600080fd5b82018360208201111561019357600080fd5b803590602001918460018302840111640100000000831117156101b557600080fd5b509092509050610355565b61013e610492565b61013e610498565b610240600480360360208110156101e657600080fd5b81019060208101813564010000000081111561020157600080fd5b82018360208201111561021357600080fd5b8035906020019184600183028401116401000000008311171561023557600080fd5b50909250905061049e565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561028557818101518382015260200161026d565b50505050905090810190601f1680156102b25780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b6102de600480360360208110156102d757600080fd5b5035610555565b604080519115158252519081900360200190f35b6101176004803603604081101561030857600080fd5b508035906020013561056a565b61013e610575565b61013e61057b565b61013e610581565b6102de610587565b610117610596565b61013e6105a0565b600455565b600555565b60045481565b60005a905060006103646105a6565b60005460015460408051841515815232602082015280820193909352606083019190915243608083018190529051929350917fbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc09181900360a00190a1816103ca57600080fd5b6000546103d75760008190555b6003546002026103e56105ca565b816103ec57fe5b068101600190810181556007805490910190557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b6005545a8403101561048b578040600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01610422565b5050505050565b60015481565b60025481565b6000606060005a90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff430160005b6004545a84031015610522578080156104f65750814060009081526006602052604090205460ff165b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019190506104cd565b61052a6105a6565b6040805192151560208085019190915281518085039091018152928101905297909650945050505050565b60066020526000908152604090205460ff1681565b600291909155600355565b60005481565b60035481565b60055481565b60006105916105a6565b905090565b6000808055600755565b60075490565b60008054158061059157506002546000544303108015610591575050600154431190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4301406020808301919091523082840152825180830384018152606090920190925280519101209056fea164736f6c6343000706000a", + Bin: "0x6080604052600080556000600155600060075534801561001e57600080fd5b5060405161074238038061074283398101604081905261003d9161004b565b60029190915560035561006f565b6000806040838503121561005e57600080fd5b505080516020909101519092909150565b6106c48061007e6000396000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c80637145f11b11610097578063b30566b411610066578063b30566b4146101e2578063c228a98e146101eb578063d826f88f146101f3578063e303666f1461020057600080fd5b80637145f11b146101845780637f407edf146101b7578063926f086e146101d0578063a9a4c57c146101d957600080fd5b80634585e33b116100d35780634585e33b1461013e578063523d9b8a146101515780636250a13a1461015a5780636e04ff0d1461016357600080fd5b806313bda75b146100fa5780632555d2cf1461010f5780632ff3617d14610122575b600080fd5b61010d610108366004610454565b600455565b005b61010d61011d366004610454565b600555565b61012b60045481565b6040519081526020015b60405180910390f35b61010d61014c36600461046d565b610208565b61012b60015481565b61012b60025481565b61017661017136600461046d565b610349565b6040516101359291906104df565b6101a7610192366004610454565b60066020526000908152604090205460ff1681565b6040519015158152602001610135565b61010d6101c5366004610555565b600291909155600355565b61012b60005481565b61012b60035481565b61012b60055481565b6101a76103db565b61010d6000808055600755565b60075461012b565b60005a905060006102176103ea565b60005460015460408051841515815232602082015290810192909252606082015243608082018190529192507fbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc09060a00160405180910390a18161027a57600080fd5b60005460000361028a5760008190555b6003546102989060026105a6565b6102a0610416565b6102aa91906105e3565b6102b4908261061e565b6102bf90600161061e565b600155600780549060006102d283610637565b919050555080806102e29061066f565b9150505b6005545a6102f490856106a4565b1015610342578040600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558061033a8161066f565b9150506102e6565b5050505050565b6000606060005a9050600061035f6001436106a4565b905060005b6004545a61037290856106a4565b10156103a9578080156103955750814060009081526006602052604090205460ff165b9050816103a18161066f565b925050610364565b6103b16103ea565b60408051831515602082015201604051602081830303815290604052945094505050509250929050565b60006103e56103ea565b905090565b6000805415806103e5575060025460005461040590436106a4565b1080156103e5575050600154431190565b60006104236001436106a4565b604080519140602083015230908201526060016040516020818303038152906040528051906020012060001c905090565b60006020828403121561046657600080fd5b5035919050565b6000806020838503121561048057600080fd5b823567ffffffffffffffff8082111561049857600080fd5b818501915085601f8301126104ac57600080fd5b8135818111156104bb57600080fd5b8660208285010111156104cd57600080fd5b60209290920196919550909350505050565b821515815260006020604081840152835180604085015260005b81811015610515578581018301518582016060015282016104f9565b5060006060828601015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509392505050565b6000806040838503121561056857600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156105de576105de610577565b500290565b600082610619577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b8082018082111561063157610631610577565b92915050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361066857610668610577565b5060010190565b60008161067e5761067e610577565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b818103818111156106315761063161057756fea164736f6c6343000810000a", } var UpkeepPerformCounterRestrictiveABI = UpkeepPerformCounterRestrictiveMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go index 51021b789e7..1f9ef1eda20 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2/vrf_coordinator_v2.go @@ -64,7 +64,7 @@ type VRFProof struct { var VRFCoordinatorV2MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structVRFCoordinatorV2.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"getCommitment\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentSubId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"}],\"name\":\"getFeeTier\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"internalType\":\"structVRFCoordinatorV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b50604051620059c1380380620059c18339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c61575c620002656000396000818161051901526138f00152600081816106030152613e0801526000818161036d015281816114da0152818161237701528181612dae01528181612eea015261350f015261575c6000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b604051610277939291906152a6565b60405180910390f35b61029361028e3660046150f2565b6107a5565b005b6102936102a336600461510d565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614e03565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e3000000000000000000000602082015290516102779190615251565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004614f9c565b610bb0565b6103006103ee366004614e76565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614dbb565b611385565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6103006105493660046150d9565b60009081526009602052604090205490565b610293610569366004614d00565b6115d4565b61029361057c36600461510d565b611704565b610293611951565b6102936105973660046150f2565b611a1a565b6000546001600160a01b031661038f565b6102936105bb36600461510d565b611be0565b6102b661201f565b6105db6105d63660046150f2565b612202565b6040516102779493929190615444565b6102936105f9366004614d34565b612325565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614ed4565b61257c565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614e1f565b612a16565b6103b86106c83660046150f2565b612a46565b6102936106db36600461510d565b612c3b565b6102936106ee366004614ce5565b612d75565b6107066107013660046150f2565b612fb2565b6040519015158152602001610277565b610293610724366004614ce5565b6131d5565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131e6565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613242565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131e6565b604080518082018252600091610a22919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca6156f1565b90600052602060002001541415610b55576007805460009190610aef906001906155ab565b81548110610aff57610aff6156f1565b906000526020600020015490508060078381548110610b2057610b206156f1565b6000918252602090912001556007805480610b3d57610b3d6156c2565b60019003818190600052602060002001600090559055505b80610b5f816155ef565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131e6565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f97918991899189918991899190615305565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec826001615507565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925081611262613667565b60408051602081019390935282015267ffffffffffffffff8a16606082015263ffffffff8089166080830152871660a08201523360c082015260e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113cc576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff80831691161015611426576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114539084906bffffffffffffffffffffffff166155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114aa91906155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b81526004016115489291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156257600080fd5b505af1158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190614e3b565b6115d0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115dc6131e6565b60408051808201825260009161160b919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031615611660576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611760576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117ad576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f4576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600201546064141561184b576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff80891685529252909120541615611885576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119ab5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a61576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611aba576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b425767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c3c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c89576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd984612fb2565b15611d10576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d91576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dff57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611de1575b50505050509050600060018251611e1691906155ab565b905060005b8251811015611f8e57856001600160a01b0316838281518110611e4057611e406156f1565b60200260200101516001600160a01b03161415611f7c576000838381518110611e6b57611e6b6156f1565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611eb157611eb16156f1565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611f1e57611f1e6156c2565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f8e565b80611f86816155ef565b915050611e1b565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612069576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff1690600061208383615628565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156120d6578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b03918216178255955160018201805490931696169590951790559151805194955090936121ba9260028501920190614a3f565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612262576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b0390921693909291839183018282801561230f57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122f1575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561236c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123ce576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612408576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612416828401846150f2565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612472576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906124a98385615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166125009190615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461256791906154ef565b6040805192835260208301919091520161200f565b600b546000906601000000000000900460ff16156125c6576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a905060008060006125da8787613700565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561260557612605615720565b60405190808252806020026020018201604052801561262e578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126a25760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c828281518110612685576126856156f1565b60209081029190910101528061269a816155ef565b915050612634565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126ea90879086906024016153f6565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161279a9163ffffffff169084613a0e565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c9261281e928692900416615507565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006128758a600b600001600b9054906101000a900463ffffffff1663ffffffff1661286f85612a46565b3a613a5c565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128e1576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff166000908152600490915260408120805483929061291d9084906bffffffffffffffffffffffff166155c2565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261297991859116615533565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129fc939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612a299190615243565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b64575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b9957508060c0015162ffffff168367ffffffffffffffff1611155b15612ba8576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612bdd57508060e0015162ffffff168367ffffffffffffffff1611155b15612bec576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612c22575080610100015162ffffff168367ffffffffffffffff1611155b15612c31576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c97576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ce4576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612d2b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d3484612fb2565b15612d6b576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613242565b612d7d6131e6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612df857600080fd5b505afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190614e5d565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e94576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612fad576000612ea882846155ab565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612f3057600080fd5b505af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614e3b565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561304757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613029575b505050505081525050905060005b8160400151518110156131cb5760005b6007548110156131b857600061318160078381548110613087576130876156f1565b9060005260206000200154856040015185815181106130a8576130a86156f1565b60200260200101518860026000896040015189815181106130cb576130cb6156f1565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b50600081815260096020526040902054909150156131a55750600195945050505050565b50806131b0816155ef565b915050613065565b50806131c3816155ef565b915050613055565b5060009392505050565b6131dd6131e6565b61083481613b7c565b6000546001600160a01b031633146132405760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff1615613289576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b0390811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561331a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132fc575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156134145760026000856040015183815181106133a2576133a26156f1565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061340c816155ef565b91505061337b565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018201805490911690559061346f6002830182614abc565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134df9084906801000000000000000090046bffffffffffffffffffffffff166155c2565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161357d9291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561359757600080fd5b505af11580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf9190614e3b565b613605576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60004661a4b181148061367c575062066eed81145b156136f95760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b505afa1580156136cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f39190614e5d565b91505090565b4391505090565b60008060006137128560000151612a16565b6000818152600660205260409020549093506001600160a01b031680613767576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b6080860151604051613786918691602001918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526009909352912054909350806137e5576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613851968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b60405160208183030381529060405280519060200120811461389f576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006138ae8760000151613c3e565b9050806139ba5786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561393a57600080fd5b505afa15801561394e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139729190614e5d565b9050806139ba5786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b60008860800151826040516020016139dc929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050613a018982613d52565b9450505050509250925092565b60005a611388811015613a2057600080fd5b611388810390508460408204820311613a3857600080fd5b50823b613a4457600080fd5b60008083516020850160008789f190505b9392505050565b600080613a67613dbd565b905060008113613aa6576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000613ab0613ec4565b9050600082825a613ac18b8b6154ef565b613acb91906155ab565b613ad5908861556e565b613adf91906154ef565b613af190670de0b6b3a764000061556e565b613afb919061555a565b90506000613b1463ffffffff881664e8d4a5100061556e565b9050613b2c816b033b2e3c9fd0803ce80000006155ab565b821115613b65576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b6f81836154ef565b9998505050505050505050565b6001600160a01b038116331415613bd55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480613c53575062066eed81145b80613c60575062066eee81145b15613d42576101008367ffffffffffffffff16613c7b613667565b613c8591906155ab565b1180613ca25750613c94613667565b8367ffffffffffffffff1610155b15613cb05750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a829060240160206040518083038186803b158015613d0a57600080fd5b505afa158015613d1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a559190614e5d565b505067ffffffffffffffff164090565b6000613d868360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613f20565b60038360200151604051602001613d9e9291906153e2565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613e5657600080fd5b505afa158015613e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8e9190615137565b509450909250849150508015613eb25750613ea982426155ab565b8463ffffffff16105b15613ebc5750600a545b949350505050565b60004661a4b1811480613ed9575062066eed81145b15613f1857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bb57600080fd5b600091505090565b613f298961415b565b613f755760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b613f7e8861415b565b613fca5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b613fd38361415b565b61401f5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b6140288261415b565b6140745760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b614080878a8887614234565b6140cc5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b60006140d88a87614385565b905060006140eb898b878b8689896143e9565b905060006140fc838d8d8a86614515565b9050808a1461414d5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b80516000906401000003d019116141b45760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d0191161420d5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d01990800961422d8360005b6020020151614555565b1492915050565b60006001600160a01b03821661428c5760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b6020840151600090600116156142a357601c6142a6565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561435d573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61438d614ada565b6143ba600184846040516020016143a693929190615222565b604051602081830303815290604052614579565b90505b6143c68161415b565b612a105780516040805160208101929092526143e291016143a6565b90506143bd565b6143f1614ada565b825186516401000003d01990819006910614156144505760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b61445b8789886145c8565b6144a75760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b6144b28486856145c8565b6144fe5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b614509868484614710565b98975050505050505050565b600060028686868587604051602001614533969594939291906151b0565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614581614ada565b61458a826147d7565b815261459f61459a826000614223565b614812565b6020820181905260029006600114156145c3576020810180516401000003d0190390525b919050565b6000826146175760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b8351602085015160009061462d90600290615650565b1561463957601c61463c565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa1580156146bc573d6000803e3d6000fd5b5050506020604051035190506000866040516020016146db919061519e565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614718614ada565b83516020808601518551918601516000938493849361473993909190614832565b919450925090506401000003d0198582096001146147995760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d019806147b8576147b8615693565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106145c3576040805160208082019390935281518082038401815290820190915280519101206147df565b6000612a1082600261482b6401000003d01960016154ef565b901c614912565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614872838385856149d2565b909850905061488388828e886149f6565b909850905061489488828c876149f6565b909850905060006148a78d878b856149f6565b90985090506148b8888286866149d2565b90985090506148c988828e896149f6565b90985090508181146148fe576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614902565b8196505b5050505050509450945094915050565b60008061491d614af8565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a082015261494f614b16565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9250826149c85760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614aac579160200282015b82811115614aac57825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614a5f565b50614ab8929150614b34565b5090565b50805460008255906000526020600020908101906108349190614b34565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614ab85760008155600101614b35565b80356001600160a01b03811681146145c357600080fd5b8060408101831015612a1057600080fd5b600082601f830112614b8257600080fd5b6040516040810181811067ffffffffffffffff82111715614ba557614ba5615720565b8060405250808385604086011115614bbc57600080fd5b60005b6002811015614bde578135835260209283019290910190600101614bbf565b509195945050505050565b600060a08284031215614bfb57600080fd5b60405160a0810181811067ffffffffffffffff82111715614c1e57614c1e615720565b604052905080614c2d83614cb3565b8152614c3b60208401614cb3565b6020820152614c4c60408401614c9f565b6040820152614c5d60608401614c9f565b6060820152614c6e60808401614b49565b60808201525092915050565b803561ffff811681146145c357600080fd5b803562ffffff811681146145c357600080fd5b803563ffffffff811681146145c357600080fd5b803567ffffffffffffffff811681146145c357600080fd5b805169ffffffffffffffffffff811681146145c357600080fd5b600060208284031215614cf757600080fd5b613a5582614b49565b60008060608385031215614d1357600080fd5b614d1c83614b49565b9150614d2b8460208501614b60565b90509250929050565b60008060008060608587031215614d4a57600080fd5b614d5385614b49565b935060208501359250604085013567ffffffffffffffff80821115614d7757600080fd5b818701915087601f830112614d8b57600080fd5b813581811115614d9a57600080fd5b886020828501011115614dac57600080fd5b95989497505060200194505050565b60008060408385031215614dce57600080fd5b614dd783614b49565b915060208301356bffffffffffffffffffffffff81168114614df857600080fd5b809150509250929050565b600060408284031215614e1557600080fd5b613a558383614b60565b600060408284031215614e3157600080fd5b613a558383614b71565b600060208284031215614e4d57600080fd5b81518015158114613a5557600080fd5b600060208284031215614e6f57600080fd5b5051919050565b600080600080600060a08688031215614e8e57600080fd5b85359450614e9e60208701614cb3565b9350614eac60408701614c7a565b9250614eba60608701614c9f565b9150614ec860808701614c9f565b90509295509295909350565b600080828403610240811215614ee957600080fd5b6101a080821215614ef957600080fd5b614f016154c5565b9150614f0d8686614b71565b8252614f1c8660408701614b71565b60208301526080850135604083015260a0850135606083015260c08501356080830152614f4b60e08601614b49565b60a0830152610100614f5f87828801614b71565b60c0840152614f72876101408801614b71565b60e08401526101808601358184015250819350614f9186828701614be9565b925050509250929050565b6000806000806000808688036101c0811215614fb757600080fd5b614fc088614c7a565b9650614fce60208901614c9f565b9550614fdc60408901614c9f565b9450614fea60608901614c9f565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608301121561502557600080fd5b61502d6154c5565b915061503b60a08a01614c9f565b825261504960c08a01614c9f565b602083015261505a60e08a01614c9f565b604083015261010061506d818b01614c9f565b606084015261507d828b01614c9f565b608084015261508f6101408b01614c8c565b60a08401526150a16101608b01614c8c565b60c08401526150b36101808b01614c8c565b60e08401526150c56101a08b01614c8c565b818401525050809150509295509295509295565b6000602082840312156150eb57600080fd5b5035919050565b60006020828403121561510457600080fd5b613a5582614cb3565b6000806040838503121561512057600080fd5b61512983614cb3565b9150614d2b60208401614b49565b600080600080600060a0868803121561514f57600080fd5b61515886614ccb565b9450602086015193506040860151925060608601519150614ec860808701614ccb565b8060005b60028110156109e557815184526020938401939091019060010161517f565b6151a8818361517b565b604001919050565b8681526151c0602082018761517b565b6151cd606082018661517b565b6151da60a082018561517b565b6151e760e082018461517b565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b838152615232602082018461517b565b606081019190915260800192915050565b60408101612a10828461517b565b600060208083528351808285015260005b8181101561527e57858101830151858201604001528201615262565b81811115615290576000604083870101525b50601f01601f1916929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156152f7578451835293830193918301916001016152db565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a085015261535960c08501838360201c1663ffffffff169052565b61537060e08501838360401c1663ffffffff169052565b6153886101008501838360601c1663ffffffff169052565b6153a06101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613a55602083018461517b565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156154375784518352938301939183019160010161541b565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b818110156154b5578551841683529484019491840191600101615497565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff811182821017156154e9576154e9615720565b60405290565b6000821982111561550257615502615664565b500190565b600067ffffffffffffffff80831681851680830382111561552a5761552a615664565b01949350505050565b60006bffffffffffffffffffffffff80831681851680830382111561552a5761552a615664565b60008261556957615569615693565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156155a6576155a6615664565b500290565b6000828210156155bd576155bd615664565b500390565b60006bffffffffffffffffffffffff838116908316818110156155e7576155e7615664565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561562157615621615664565b5060010190565b600067ffffffffffffffff8083168181141561564657615646615664565b6001019392505050565b60008261565f5761565f615693565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60e06040523480156200001157600080fd5b5060405162005b3b38038062005b3b8339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c6158d6620002656000396000818161051901526138e70152600081816106030152613e4501526000818161036d015281816114da0152818161237701528181612dae01528181612eea015261350f01526158d66000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b604051610277939291906153b5565b60405180910390f35b61029361028e3660046151e8565b6107a5565b005b6102936102a3366004615203565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614ef9565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e30000000000000000000006020820152905161027791906153a2565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004615092565b610bb0565b6103006103ee366004614f6c565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614eb1565b611385565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6103006105493660046151cf565b60009081526009602052604090205490565b610293610569366004614df6565b6115d4565b61029361057c366004615203565b611704565b610293611951565b6102936105973660046151e8565b611a1a565b6000546001600160a01b031661038f565b6102936105bb366004615203565b611be0565b6102b661201f565b6105db6105d63660046151e8565b612202565b6040516102779493929190615553565b6102936105f9366004614e2a565b612325565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614fca565b61257c565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614f15565b612a16565b6103b86106c83660046151e8565b612a46565b6102936106db366004615203565b612c3b565b6102936106ee366004614ddb565b612d75565b6107066107013660046151e8565b612fb2565b6040519015158152602001610277565b610293610724366004614ddb565b6131d5565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131e6565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613242565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131e6565b604080518082018252600091610a22919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca615823565b90600052602060002001541415610b55576007805460009190610aef906001906156b1565b81548110610aff57610aff615823565b906000526020600020015490508060078381548110610b2057610b20615823565b6000918252602090912001556007805480610b3d57610b3d6157f4565b60019003818190600052602060002001600090559055505b80610b5f81615721565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131e6565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f97918991899189918991899190615414565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec826001615616565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925081611262613667565b60408051602081019390935282015267ffffffffffffffff8a16606082015263ffffffff8089166080830152871660a08201523360c082015260e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113cc576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff80831691161015611426576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114539084906bffffffffffffffffffffffff166156c8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114aa91906156c8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b81526004016115489291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156257600080fd5b505af1158015611576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159a9190614f31565b6115d0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115dc6131e6565b60408051808201825260009161160b919084906002908390839080828437600092019190915250612a16915050565b6000818152600660205260409020549091506001600160a01b031615611660576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611760576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117ad576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f4576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600201546064141561184b576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff80891685529252909120541615611885576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119ab5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a61576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611aba576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b425767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c3c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c89576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd984612fb2565b15611d10576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d91576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dff57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611de1575b50505050509050600060018251611e1691906156b1565b905060005b8251811015611f8e57856001600160a01b0316838281518110611e4057611e40615823565b60200260200101516001600160a01b03161415611f7c576000838381518110611e6b57611e6b615823565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611eb157611eb1615823565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611f1e57611f1e6157f4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f8e565b80611f8681615721565b915050611e1b565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612069576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff169060006120838361575a565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156120d6578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b03918216178255955160018201805490931696169590951790559151805194955090936121ba9260028501920190614b35565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612262576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b0390921693909291839183018282801561230f57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122f1575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561236c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123ce576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612408576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612416828401846151e8565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612472576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906124a98385615639565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166125009190615639565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461256791906155fe565b6040805192835260208301919091520161200f565b600b546000906601000000000000900460ff16156125c6576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a905060008060006125da87876136f7565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561260557612605615852565b60405190808252806020026020018201604052801561262e578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126a25760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c82828151811061268557612685615823565b60209081029190910101528061269a81615721565b915050612634565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126ea9087908690602401615505565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161279a9163ffffffff169084613a05565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c9261281e928692900416615616565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060006128758a600b600001600b9054906101000a900463ffffffff1663ffffffff1661286f85612a46565b3a613a53565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128e1576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff166000908152600490915260408120805483929061291d9084906bffffffffffffffffffffffff166156c8565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261297991859116615639565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129fc939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612a299190615394565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b64575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b9957508060c0015162ffffff168367ffffffffffffffff1611155b15612ba8576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612bdd57508060e0015162ffffff168367ffffffffffffffff1611155b15612bec576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612c22575080610100015162ffffff168367ffffffffffffffff1611155b15612c31576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c97576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ce4576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612d2b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d3484612fb2565b15612d6b576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613242565b612d7d6131e6565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612df857600080fd5b505afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190614f53565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e94576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612fad576000612ea882846156b1565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612f3057600080fd5b505af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614f31565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561304757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613029575b505050505081525050905060005b8160400151518110156131cb5760005b6007548110156131b85760006131816007838154811061308757613087615823565b9060005260206000200154856040015185815181106130a8576130a8615823565b60200260200101518860026000896040015189815181106130cb576130cb615823565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b50600081815260096020526040902054909150156131a55750600195945050505050565b50806131b081615721565b915050613065565b50806131c381615721565b915050613055565b5060009392505050565b6131dd6131e6565b61083481613bab565b6000546001600160a01b031633146132405760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff1615613289576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b0390811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561331a57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132fc575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156134145760026000856040015183815181106133a2576133a2615823565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061340c81615721565b91505061337b565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018201805490911690559061346f6002830182614bb2565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134df9084906801000000000000000090046bffffffffffffffffffffffff166156c8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161357d9291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561359757600080fd5b505af11580156135ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135cf9190614f31565b613605576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60004661367381613c6d565b156136f05760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156136b257600080fd5b505afa1580156136c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136ea9190614f53565b91505090565b4391505090565b60008060006137098560000151612a16565b6000818152600660205260409020549093506001600160a01b03168061375e576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b608086015160405161377d918691602001918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526009909352912054909350806137dc576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613848968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b604051602081830303815290604052805190602001208114613896576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006138a58760000151613c90565b9050806139b15786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561393157600080fd5b505afa158015613945573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139699190614f53565b9050806139b15786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b60008860800151826040516020016139d3929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506139f88982613d8f565b9450505050509250925092565b60005a611388811015613a1757600080fd5b611388810390508460408204820311613a2f57600080fd5b50823b613a3b57600080fd5b60008083516020850160008789f190505b9392505050565b600080613a5e613dfa565b905060008113613a9d576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000613adf6000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613f0192505050565b9050600082825a613af08b8b6155fe565b613afa91906156b1565b613b049088615674565b613b0e91906155fe565b613b2090670de0b6b3a7640000615674565b613b2a9190615660565b90506000613b4363ffffffff881664e8d4a51000615674565b9050613b5b816b033b2e3c9fd0803ce80000006156b1565b821115613b94576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613b9e81836155fe565b9998505050505050505050565b6001600160a01b038116331415613c045760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480613c81575062066eed82145b80612a1057505062066eee1490565b600046613c9c81613c6d565b15613d7f576101008367ffffffffffffffff16613cb7613667565b613cc191906156b1565b1180613cde5750613cd0613667565b8367ffffffffffffffff1610155b15613cec5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152606490632b407a82906024015b60206040518083038186803b158015613d4757600080fd5b505afa158015613d5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a4c9190614f53565b505067ffffffffffffffff164090565b6000613dc38360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613fdc565b60038360200151604051602001613ddb9291906154f1565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613e9357600080fd5b505afa158015613ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ecb919061522d565b509450909250849150508015613eef5750613ee682426156b1565b8463ffffffff16105b15613ef95750600a545b949350505050565b600046613f0d81613c6d565b15613f4c57606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613d4757600080fd5b613f5581614217565b15613fd35773420000000000000000000000000000000000000f6001600160a01b03166349948e0e8460405180608001604052806048815260200161588260489139604051602001613fa89291906152d2565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613d2f91906153a2565b50600092915050565b613fe589614251565b6140315760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b61403a88614251565b6140865760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b61408f83614251565b6140db5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b6140e482614251565b6141305760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b61413c878a888761432a565b6141885760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b60006141948a8761447b565b905060006141a7898b878b8689896144df565b905060006141b8838d8d8a8661460b565b9050808a146142095760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b6000600a82148061422957506101a482145b80614236575062aa37dc82145b80614242575061210582145b80612a1057505062014a331490565b80516000906401000003d019116142aa5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d019116143035760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d0199080096143238360005b602002015161464b565b1492915050565b60006001600160a01b0382166143825760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b60208401516000906001161561439957601c61439c565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614453573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614483614bd0565b6144b06001848460405160200161449c93929190615373565b60405160208183030381529060405261466f565b90505b6144bc81614251565b612a105780516040805160208101929092526144d8910161449c565b90506144b3565b6144e7614bd0565b825186516401000003d01990819006910614156145465760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b6145518789886146be565b61459d5760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b6145a88486856146be565b6145f45760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b6145ff868484614806565b98975050505050505050565b60006002868686858760405160200161462996959493929190615301565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614677614bd0565b614680826148cd565b8152614695614690826000614319565b614908565b6020820181905260029006600114156146b9576020810180516401000003d0190390525b919050565b60008261470d5760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b8351602085015160009061472390600290615782565b1561472f57601c614732565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa1580156147b2573d6000803e3d6000fd5b5050506020604051035190506000866040516020016147d191906152c0565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b61480e614bd0565b83516020808601518551918601516000938493849361482f93909190614928565b919450925090506401000003d01985820960011461488f5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d019806148ae576148ae6157c5565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106146b9576040805160208082019390935281518082038401815290820190915280519101206148d5565b6000612a108260026149216401000003d01960016155fe565b901c614a08565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a089050600061496883838585614ac8565b909850905061497988828e88614aec565b909850905061498a88828c87614aec565b9098509050600061499d8d878b85614aec565b90985090506149ae88828686614ac8565b90985090506149bf88828e89614aec565b90985090508181146149f4576401000003d019818a0998506401000003d01982890997506401000003d01981830996506149f8565b8196505b5050505050509450945094915050565b600080614a13614bee565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614a45614c0c565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa925082614abe5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614ba2579160200282015b82811115614ba257825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614b55565b50614bae929150614c2a565b5090565b50805460008255906000526020600020908101906108349190614c2a565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614bae5760008155600101614c2b565b80356001600160a01b03811681146146b957600080fd5b8060408101831015612a1057600080fd5b600082601f830112614c7857600080fd5b6040516040810181811067ffffffffffffffff82111715614c9b57614c9b615852565b8060405250808385604086011115614cb257600080fd5b60005b6002811015614cd4578135835260209283019290910190600101614cb5565b509195945050505050565b600060a08284031215614cf157600080fd5b60405160a0810181811067ffffffffffffffff82111715614d1457614d14615852565b604052905080614d2383614da9565b8152614d3160208401614da9565b6020820152614d4260408401614d95565b6040820152614d5360608401614d95565b6060820152614d6460808401614c3f565b60808201525092915050565b803561ffff811681146146b957600080fd5b803562ffffff811681146146b957600080fd5b803563ffffffff811681146146b957600080fd5b803567ffffffffffffffff811681146146b957600080fd5b805169ffffffffffffffffffff811681146146b957600080fd5b600060208284031215614ded57600080fd5b613a4c82614c3f565b60008060608385031215614e0957600080fd5b614e1283614c3f565b9150614e218460208501614c56565b90509250929050565b60008060008060608587031215614e4057600080fd5b614e4985614c3f565b935060208501359250604085013567ffffffffffffffff80821115614e6d57600080fd5b818701915087601f830112614e8157600080fd5b813581811115614e9057600080fd5b886020828501011115614ea257600080fd5b95989497505060200194505050565b60008060408385031215614ec457600080fd5b614ecd83614c3f565b915060208301356bffffffffffffffffffffffff81168114614eee57600080fd5b809150509250929050565b600060408284031215614f0b57600080fd5b613a4c8383614c56565b600060408284031215614f2757600080fd5b613a4c8383614c67565b600060208284031215614f4357600080fd5b81518015158114613a4c57600080fd5b600060208284031215614f6557600080fd5b5051919050565b600080600080600060a08688031215614f8457600080fd5b85359450614f9460208701614da9565b9350614fa260408701614d70565b9250614fb060608701614d95565b9150614fbe60808701614d95565b90509295509295909350565b600080828403610240811215614fdf57600080fd5b6101a080821215614fef57600080fd5b614ff76155d4565b91506150038686614c67565b82526150128660408701614c67565b60208301526080850135604083015260a0850135606083015260c0850135608083015261504160e08601614c3f565b60a083015261010061505587828801614c67565b60c0840152615068876101408801614c67565b60e0840152610180860135818401525081935061508786828701614cdf565b925050509250929050565b6000806000806000808688036101c08112156150ad57600080fd5b6150b688614d70565b96506150c460208901614d95565b95506150d260408901614d95565b94506150e060608901614d95565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608301121561511b57600080fd5b6151236155d4565b915061513160a08a01614d95565b825261513f60c08a01614d95565b602083015261515060e08a01614d95565b6040830152610100615163818b01614d95565b6060840152615173828b01614d95565b60808401526151856101408b01614d82565b60a08401526151976101608b01614d82565b60c08401526151a96101808b01614d82565b60e08401526151bb6101a08b01614d82565b818401525050809150509295509295509295565b6000602082840312156151e157600080fd5b5035919050565b6000602082840312156151fa57600080fd5b613a4c82614da9565b6000806040838503121561521657600080fd5b61521f83614da9565b9150614e2160208401614c3f565b600080600080600060a0868803121561524557600080fd5b61524e86614dc1565b9450602086015193506040860151925060608601519150614fbe60808701614dc1565b8060005b60028110156109e5578151845260209384019390910190600101615275565b600081518084526152ac8160208601602086016156f5565b601f01601f19169290920160200192915050565b6152ca8183615271565b604001919050565b600083516152e48184602088016156f5565b8351908301906152f88183602088016156f5565b01949350505050565b8681526153116020820187615271565b61531e6060820186615271565b61532b60a0820185615271565b61533860e0820184615271565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b8381526153836020820184615271565b606081019190915260800192915050565b60408101612a108284615271565b602081526000613a4c6020830184615294565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615406578451835293830193918301916001016153ea565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a085015261546860c08501838360201c1663ffffffff169052565b61547f60e08501838360401c1663ffffffff169052565b6154976101008501838360601c1663ffffffff169052565b6154af6101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613a4c6020830184615271565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156155465784518352938301939183019160010161552a565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b818110156155c45785518416835294840194918401916001016155a6565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff811182821017156155f8576155f8615852565b60405290565b6000821982111561561157615611615796565b500190565b600067ffffffffffffffff8083168185168083038211156152f8576152f8615796565b60006bffffffffffffffffffffffff8083168185168083038211156152f8576152f8615796565b60008261566f5761566f6157c5565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156156ac576156ac615796565b500290565b6000828210156156c3576156c3615796565b500390565b60006bffffffffffffffffffffffff838116908316818110156156ed576156ed615796565b039392505050565b60005b838110156157105781810151838201526020016156f8565b838111156109e55750506000910152565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561575357615753615796565b5060010190565b600067ffffffffffffffff8083168181141561577857615778615796565b6001019392505050565b600082615791576157916157c5565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var VRFCoordinatorV2ABI = VRFCoordinatorV2MetaData.ABI diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go index d4da270386e..e09c7c46e29 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go @@ -67,7 +67,7 @@ type VRFV2PlusClientRandomWordsRequest struct { var VRFCoordinatorV25MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2_5.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200615938038062006159833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f7e620001db600039600081816106150152613a860152615f7e6000f3fe6080604052600436106102dc5760003560e01c806379ba50971161017f578063b08c8795116100e1578063da2f26101161008a578063e72f6e3011610064578063e72f6e3014610964578063ee9d2d3814610984578063f2fde38b146109b157600080fd5b8063da2f2610146108dd578063dac83d2914610913578063dc311dd31461093357600080fd5b8063caf70c4a116100bb578063caf70c4a1461087d578063cb6317971461089d578063d98e620e146108bd57600080fd5b8063b08c87951461081d578063b2a7cac51461083d578063bec4c08c1461085d57600080fd5b80639b1c385e11610143578063a4c0ed361161011d578063a4c0ed36146107b0578063aa433aff146107d0578063aefb212f146107f057600080fd5b80639b1c385e146107435780639d40a6fd14610763578063a21a23e41461079b57600080fd5b806379ba5097146106bd5780638402595e146106d257806386fe91c7146106f25780638da5cb5b1461071257806395b55cfc1461073057600080fd5b8063330987b31161024357806365982744116101ec5780636b6feccc116101c65780636b6feccc146106375780636f64f03f1461067d57806372e9d5651461069d57600080fd5b806365982744146105c357806366316d8d146105e3578063689c45171461060357600080fd5b806341af6c871161021d57806341af6c871461055e5780635d06b4ab1461058e57806364d51a2a146105ae57600080fd5b8063330987b3146104f3578063405b84fa1461051357806340d6bb821461053357600080fd5b80630ae09540116102a55780631b6b6d231161027f5780631b6b6d231461047f57806329492657146104b7578063294daa49146104d757600080fd5b80630ae09540146103f857806315c48b841461041857806318e3dd271461044057600080fd5b8062012291146102e157806304104edb1461030e578063043bd6ae14610330578063088070f51461035457806308821d58146103d8575b600080fd5b3480156102ed57600080fd5b506102f66109d1565b60405161030593929190615ae2565b60405180910390f35b34801561031a57600080fd5b5061032e61032936600461542f565b610a4d565b005b34801561033c57600080fd5b5061034660115481565b604051908152602001610305565b34801561036057600080fd5b50600d546103a09061ffff81169063ffffffff62010000820481169160ff600160301b820416916701000000000000008204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610305565b3480156103e457600080fd5b5061032e6103f336600461556f565b610c0f565b34801561040457600080fd5b5061032e610413366004615811565b610da3565b34801561042457600080fd5b5061042d60c881565b60405161ffff9091168152602001610305565b34801561044c57600080fd5b50600a5461046790600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610305565b34801561048b57600080fd5b5060025461049f906001600160a01b031681565b6040516001600160a01b039091168152602001610305565b3480156104c357600080fd5b5061032e6104d236600461544c565b610e71565b3480156104e357600080fd5b5060405160018152602001610305565b3480156104ff57600080fd5b5061046761050e366004615641565b610fee565b34801561051f57600080fd5b5061032e61052e366004615811565b6114d8565b34801561053f57600080fd5b506105496101f481565b60405163ffffffff9091168152602001610305565b34801561056a57600080fd5b5061057e6105793660046155c4565b6118ff565b6040519015158152602001610305565b34801561059a57600080fd5b5061032e6105a936600461542f565b611b00565b3480156105ba57600080fd5b5061042d606481565b3480156105cf57600080fd5b5061032e6105de366004615481565b611bbe565b3480156105ef57600080fd5b5061032e6105fe36600461544c565b611c1e565b34801561060f57600080fd5b5061049f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561064357600080fd5b506012546106609063ffffffff8082169164010000000090041682565b6040805163ffffffff938416815292909116602083015201610305565b34801561068957600080fd5b5061032e6106983660046154ba565b611de6565b3480156106a957600080fd5b5060035461049f906001600160a01b031681565b3480156106c957600080fd5b5061032e611ee5565b3480156106de57600080fd5b5061032e6106ed36600461542f565b611f96565b3480156106fe57600080fd5b50600a54610467906001600160601b031681565b34801561071e57600080fd5b506000546001600160a01b031661049f565b61032e61073e3660046155c4565b6120b1565b34801561074f57600080fd5b5061034661075e36600461571e565b6121f8565b34801561076f57600080fd5b50600754610783906001600160401b031681565b6040516001600160401b039091168152602001610305565b3480156107a757600080fd5b506103466125ed565b3480156107bc57600080fd5b5061032e6107cb3660046154e7565b61283d565b3480156107dc57600080fd5b5061032e6107eb3660046155c4565b6129dd565b3480156107fc57600080fd5b5061081061080b366004615836565b612a3d565b6040516103059190615a47565b34801561082957600080fd5b5061032e610838366004615773565b612b3e565b34801561084957600080fd5b5061032e6108583660046155c4565b612cd2565b34801561086957600080fd5b5061032e610878366004615811565b612e00565b34801561088957600080fd5b5061034661089836600461558b565b612f9c565b3480156108a957600080fd5b5061032e6108b8366004615811565b612fcc565b3480156108c957600080fd5b506103466108d83660046155c4565b6132cf565b3480156108e957600080fd5b5061049f6108f83660046155c4565b600e602052600090815260409020546001600160a01b031681565b34801561091f57600080fd5b5061032e61092e366004615811565b6132f0565b34801561093f57600080fd5b5061095361094e3660046155c4565b61340f565b604051610305959493929190615c4a565b34801561097057600080fd5b5061032e61097f36600461542f565b61350a565b34801561099057600080fd5b5061034661099f3660046155c4565b60106020526000908152604090205481565b3480156109bd57600080fd5b5061032e6109cc36600461542f565b6136f2565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff16939192839190830182828015610a3b57602002820191906000526020600020905b815481526020019060010190808311610a27575b50505050509050925092509250909192565b610a55613703565b60135460005b81811015610be257826001600160a01b031660138281548110610a8057610a80615f22565b6000918252602090912001546001600160a01b03161415610bd0576013610aa8600184615e1b565b81548110610ab857610ab8615f22565b600091825260209091200154601380546001600160a01b039092169183908110610ae457610ae4615f22565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610b1b600185615e1b565b81548110610b2b57610b2b615f22565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610b6a57610b6a615f0c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03851681527ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af37910160405180910390a1505050565b80610bda81615e8a565b915050610a5b565b50604051635428d44960e01b81526001600160a01b03831660048201526024015b60405180910390fd5b50565b610c17613703565b604080518082018252600091610c46919084906002908390839080828437600092019190915250612f9c915050565b6000818152600e60205260409020549091506001600160a01b031680610c8257604051631dfd6e1360e21b815260048101839052602401610c03565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610d5a5782600f8281548110610cbd57610cbd615f22565b90600052602060002001541415610d4857600f805460009190610ce290600190615e1b565b81548110610cf257610cf2615f22565b9060005260206000200154905080600f8381548110610d1357610d13615f22565b600091825260209091200155600f805480610d3057610d30615f0c565b60019003818190600052602060002001600090559055505b80610d5281615e8a565b915050610c9f565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610d9691815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610ddb57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610e0f57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615610e3a5760405163769dd35360e11b815260040160405180910390fd5b610e43846118ff565b15610e6157604051631685ecdd60e31b815260040160405180910390fd5b610e6b848461375f565b50505050565b600d54600160301b900460ff1615610e9c5760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b0380831691161015610ed857604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290610f009084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610f489190615e32565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610fc2576040519150601f19603f3d011682016040523d82523d6000602084013e610fc7565b606091505b5050905080610fe95760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff161561101c5760405163769dd35360e11b815260040160405180910390fd5b60005a9050600061102d858561391b565b90506000846060015163ffffffff166001600160401b0381111561105357611053615f38565b60405190808252806020026020018201604052801561107c578160200160208202803683370190505b50905060005b856060015163ffffffff168110156110fc578260400151816040516020016110b4929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c8282815181106110df576110df615f22565b6020908102919091010152806110f481615e8a565b915050611082565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b9161113491908690602401615b55565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805466ff0000000000001916600160301b17905590880151608089015191925060009161119c9163ffffffff169084613ba8565b600d805466ff00000000000019169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b03166111df816001615d9b565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a0151805161122c90600190615e1b565b8151811061123c5761123c615f22565b602091010151600d5460f89190911c600114915060009061126d908a90600160581b900463ffffffff163a85613bf6565b90508115611376576020808c01516000908152600690915260409020546001600160601b03808316600160601b9092041610156112bd57604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c906112f4908490600160601b90046001600160601b0316615e32565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c90915281208054859450909261134d91859116615dc6565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550611462565b6020808c01516000908152600690915260409020546001600160601b03808316911610156113b757604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906113e49084906001600160601b0316615e32565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b90915281208054859450909261143d91859116615dc6565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a6040015184886040516114bf939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156115035760405163769dd35360e11b815260040160405180910390fd5b61150c81613c46565b61153457604051635428d44960e01b81526001600160a01b0382166004820152602401610c03565b6000806000806115438661340f565b945094505093509350336001600160a01b0316826001600160a01b0316146115ad5760405162461bcd60e51b815260206004820152601660248201527f4e6f7420737562736372697074696f6e206f776e6572000000000000000000006044820152606401610c03565b6115b6866118ff565b156116035760405162461bcd60e51b815260206004820152601660248201527f50656e64696e67207265717565737420657869737473000000000000000000006044820152606401610c03565b60006040518060c00160405280611618600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161166c9190615a6d565b604051602081830303815290604052905061168688613cb0565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906116bf908590600401615a5a565b6000604051808303818588803b1580156116d857600080fd5b505af11580156116ec573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611715905057506001600160601b03861615155b156117f45760025460405163a9059cbb60e01b81526001600160a01b0389811660048301526001600160601b03891660248301529091169063a9059cbb90604401602060405180830381600087803b15801561177057600080fd5b505af1158015611784573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a891906155a7565b6117f45760405162461bcd60e51b815260206004820152601260248201527f696e73756666696369656e742066756e647300000000000000000000000000006044820152606401610c03565b600d805466ff0000000000001916600160301b17905560005b83518110156118a25783818151811061182857611828615f22565b6020908102919091010151604051638ea9811760e01b81526001600160a01b038a8116600483015290911690638ea9811790602401600060405180830381600087803b15801561187757600080fd5b505af115801561188b573d6000803e3d6000fd5b50505050808061189a90615e8a565b91505061180d565b50600d805466ff00000000000019169055604080516001600160a01b0389168152602081018a90527fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187910160405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561198957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161196b575b505050505081525050905060005b816040015151811015611af65760005b600f54811015611ae3576000611aac600f83815481106119c9576119c9615f22565b9060005260206000200154856040015185815181106119ea576119ea615f22565b6020026020010151886004600089604001518981518110611a0d57611a0d615f22565b6020908102919091018101516001600160a01b03908116835282820193909352604091820160009081208e82528252829020548251808301889052959093168583015260608501939093526001600160401b039091166080808501919091528151808503909101815260a08401825280519083012060c084019490945260e0808401859052815180850390910181526101009093019052815191012091565b5060008181526010602052604090205490915015611ad05750600195945050505050565b5080611adb81615e8a565b9150506119a7565b5080611aee81615e8a565b915050611997565b5060009392505050565b611b08613703565b611b1181613c46565b15611b3a5760405163ac8a27ef60e01b81526001600160a01b0382166004820152602401610c03565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383169081179091556040519081527fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259060200160405180910390a150565b611bc6613703565b6002546001600160a01b031615611bf057604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff1615611c495760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611c725760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611cae57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611cd69084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611d1e9190615e32565b82546101009290920a6001600160601b0381810219909316918316021790915560025460405163a9059cbb60e01b81526001600160a01b03868116600483015292851660248201529116915063a9059cbb90604401602060405180830381600087803b158015611d8d57600080fd5b505af1158015611da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc591906155a7565b611de257604051631e9acf1760e31b815260040160405180910390fd5b5050565b611dee613703565b604080518082018252600091611e1d919084906002908390839080828437600092019190915250612f9c915050565b6000818152600e60205260409020549091506001600160a01b031615611e5957604051634a0b8fa760e01b815260048101829052602401610c03565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610d96565b6001546001600160a01b03163314611f3f5760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c03565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611f9e613703565b600a544790600160601b90046001600160601b031681811115611fde576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015610fe9576000611ff28284615e1b565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114612041576040519150601f19603f3d011682016040523d82523d6000602084013e612046565b606091505b50509050806120685760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b0387168152602081018490527f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c910160405180910390a15050505050565b600d54600160301b900460ff16156120dc5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661211157604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c6121408385615dc6565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b03166121889190615dc6565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e9028234846121db9190615d83565b604080519283526020830191909152015b60405180910390a25050565b600d54600090600160301b900460ff16156122265760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b031661226157604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b0316806122b2576040516379bfd40160e01b815260208401356004820152336024820152604401610c03565b600d5461ffff166122c96060850160408601615758565b61ffff1610806122ec575060c86122e66060850160408601615758565b61ffff16115b15612332576123016060840160408501615758565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610c03565b600d5462010000900463ffffffff166123516080850160608601615858565b63ffffffff1611156123a15761236d6080840160608501615858565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610c03565b6101f46123b460a0850160808601615858565b63ffffffff1611156123fa576123d060a0840160808501615858565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610c03565b6000612407826001615d9b565b604080518635602080830182905233838501528089013560608401526001600160401b0385166080808501919091528451808503909101815260a0808501865281519183019190912060c085019390935260e0808501849052855180860390910181526101009094019094528251920191909120929350906000906124979061249290890189615c9f565b613eff565b905060006124a482613f7c565b9050836124af613fed565b60208a01356124c460808c0160608d01615858565b6124d460a08d0160808e01615858565b33866040516020016124ec9796959493929190615bad565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d60400160208101906125639190615758565b8e60600160208101906125769190615858565b8f60800160208101906125899190615858565b8960405161259c96959493929190615b6e565b60405180910390a450503360009081526004602090815260408083208983013584529091529020805467ffffffffffffffff19166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff161561261b5760405163769dd35360e11b815260040160405180910390fd5b600033612629600143615e1b565b600754604051606093841b6bffffffffffffffffffffffff199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b039091169060006126a883615ea5565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b038111156126e7576126e7615f38565b604051908082528060200260200182016040528015612710578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b0392831617835592516001830180549094169116179091559251805194955090936127f19260028501920190615145565b5061280191506008905083614086565b5060405133815282907f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d9060200160405180910390a250905090565b600d54600160301b900460ff16156128685760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612893576040516344b0e3c360e01b815260040160405180910390fd5b602081146128b457604051638129bbcd60e01b815260040160405180910390fd5b60006128c2828401846155c4565b6000818152600560205260409020549091506001600160a01b03166128fa57604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906129218385615dc6565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166129699190615dc6565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846129bc9190615d83565b604080519283526020830191909152015b60405180910390a2505050505050565b6129e5613703565b6000818152600560205260409020546001600160a01b0316612a1a57604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610c0c9082906001600160a01b031661375f565b60606000612a4b6008614092565b9050808410612a6d57604051631390f2a160e01b815260040160405180910390fd5b6000612a798486615d83565b905081811180612a87575083155b612a915780612a93565b815b90506000612aa18683615e1b565b6001600160401b03811115612ab857612ab8615f38565b604051908082528060200260200182016040528015612ae1578160200160208202803683370190505b50905060005b8151811015612b3457612b05612afd8883615d83565b60089061409c565b828281518110612b1757612b17615f22565b602090810291909101015280612b2c81615e8a565b915050612ae7565b5095945050505050565b612b46613703565b60c861ffff87161115612b805760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610c03565b60008213612ba4576040516321ea67b360e11b815260048101839052602401610c03565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff19168817620100008702176effffffffffffffffff000000000000191667010000000000000085026effffffff0000000000000000000000191617600160581b83021790558a51601280548d87015192891667ffffffffffffffff199091161764010000000092891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612cfd5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612d3257604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612d8b576000818152600560205260409081902060010154905163d084e97560e01b81526001600160a01b039091166004820152602401610c03565b6000818152600560209081526040918290208054336001600160a01b0319808316821784556001909301805490931690925583516001600160a01b0390911680825292810191909152909183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691016121ec565b60008281526005602052604090205482906001600160a01b031680612e3857604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612e6c57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff1615612e975760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612eca576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612f0157610e6b565b6001600160a01b03831660008181526004602090815260408083208884528252808320805467ffffffffffffffff19166001908117909155600583528184206002018054918201815584529282902090920180546001600160a01b03191684179055905191825285917f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e191015b60405180910390a250505050565b600081604051602001612faf9190615a39565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b03168061300457604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461303857604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff16156130635760405163769dd35360e11b815260040160405180910390fd5b61306c846118ff565b1561308a57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b03166130e6576040516379bfd40160e01b8152600481018590526001600160a01b0384166024820152604401610c03565b60008481526005602090815260408083206002018054825181850281018501909352808352919290919083018282801561314957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161312b575b505050505090506000600182516131609190615e1b565b905060005b825181101561326c57856001600160a01b031683828151811061318a5761318a615f22565b60200260200101516001600160a01b0316141561325a5760008383815181106131b5576131b5615f22565b6020026020010151905080600560008a815260200190815260200160002060020183815481106131e7576131e7615f22565b600091825260208083209190910180546001600160a01b0319166001600160a01b03949094169390931790925589815260059091526040902060020180548061323257613232615f0c565b600082815260209020810160001990810180546001600160a01b03191690550190555061326c565b8061326481615e8a565b915050613165565b506001600160a01b03851660008181526004602090815260408083208a8452825291829020805467ffffffffffffffff19169055905191825287917f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a791016129cd565b600f81815481106132df57600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03168061332857604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461335c57604051636c51fda960e11b81526001600160a01b0382166004820152602401610c03565b600d54600160301b900460ff16156133875760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610e6b5760008481526005602090815260409182902060010180546001600160a01b0319166001600160a01b03871690811790915582513381529182015285917f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19101612f8e565b6000818152600560205260408120548190819081906060906001600160a01b031661344d57604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156134f057602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116134d2575b505050505090509450945094509450945091939590929450565b613512613703565b6002546001600160a01b031661353b5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561357f57600080fd5b505afa158015613593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b791906155dd565b600a549091506001600160601b0316818111156135f1576040516354ced18160e11b81526004810182905260248101839052604401610c03565b81811015610fe95760006136058284615e1b565b60025460405163a9059cbb60e01b81526001600160a01b0387811660048301526024820184905292935091169063a9059cbb90604401602060405180830381600087803b15801561365557600080fd5b505af1158015613669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368d91906155a7565b6136aa57604051631f01ff1360e21b815260040160405180910390fd5b604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b6136fa613703565b610c0c816140a8565b6000546001600160a01b0316331461375d5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c03565b565b60008061376b84613cb0565b60025491935091506001600160a01b03161580159061379257506001600160601b03821615155b156138425760025460405163a9059cbb60e01b81526001600160a01b0385811660048301526001600160601b03851660248301529091169063a9059cbb90604401602060405180830381600087803b1580156137ed57600080fd5b505af1158015613801573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061382591906155a7565b61384257604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613898576040519150601f19603f3d011682016040523d82523d6000602084013e61389d565b606091505b50509050806138bf5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006139478460000151612f9c565b6000818152600e60205260409020549091506001600160a01b03168061398357604051631dfd6e1360e21b815260048101839052602401610c03565b60008286608001516040516020016139a5929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806139eb57604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613a1a978a979096959101615bf7565b604051602081830303815290604052805190602001208114613a4f5760405163354a450b60e21b815260040160405180910390fd5b6000613a5e8760000151614152565b905080613b36578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b158015613ad057600080fd5b505afa158015613ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0891906155dd565b905080613b3657865160405163175dadad60e01b81526001600160401b039091166004820152602401610c03565b6000886080015182604051602001613b58929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506000613b7f8a83614249565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a611388811015613bba57600080fd5b611388810390508460408204820311613bd257600080fd5b50823b613bde57600080fd5b60008083516020850160008789f190505b9392505050565b60008115613c2457601254613c1d9086908690640100000000900463ffffffff16866142b4565b9050613c3e565b601254613c3b908690869063ffffffff168661431e565b90505b949350505050565b6000805b601354811015613ca757826001600160a01b031660138281548110613c7157613c71615f22565b6000918252602090912001546001600160a01b03161415613c955750600192915050565b80613c9f81615e8a565b915050613c4a565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613d3c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d1e575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613e19576004600084604001518381518110613dc857613dc8615f22565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020805467ffffffffffffffff1916905580613e1181615e8a565b915050613da1565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613e5160028301826151aa565b5050600085815260066020526040812055613e6d60088661440c565b50600a8054859190600090613e8c9084906001600160601b0316615e32565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613ed49190615e32565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081019091526000815281613f2857506040805160208101909152600081526114d2565b63125fa26760e31b613f3a8385615e5a565b6001600160e01b03191614613f6257604051632923fee760e11b815260040160405180910390fd5b613f6f8260048186615d59565b810190613bef91906155f6565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613fb591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480614002575062066eed81145b1561407f5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b505afa158015614055573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061407991906155dd565b91505090565b4391505090565b6000613bef8383614418565b60006114d2825490565b6000613bef8383614467565b6001600160a01b0381163314156141015760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c03565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480614167575062066eed81145b80614174575062066eee81145b1561423a57610100836001600160401b031661418e613fed565b6141989190615e1b565b11806141b457506141a7613fed565b836001600160401b031610155b156141c25750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a829060240160206040518083038186803b15801561420257600080fd5b505afa158015614216573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bef91906155dd565b50506001600160401b03164090565b600061427d8360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614491565b60038360200151604051602001614295929190615b41565b60408051601f1981840301815291905280516020909101209392505050565b6000806142bf6146bc565b905060005a6142ce8888615d83565b6142d89190615e1b565b6142e29085615dfc565b905060006142fb63ffffffff871664e8d4a51000615dfc565b9050826143088284615d83565b6143129190615d83565b98975050505050505050565b600080614329614718565b90506000811361434f576040516321ea67b360e11b815260048101829052602401610c03565b60006143596146bc565b9050600082825a61436a8b8b615d83565b6143749190615e1b565b61437e9088615dfc565b6143889190615d83565b61439a90670de0b6b3a7640000615dfc565b6143a49190615de8565b905060006143bd63ffffffff881664e8d4a51000615dfc565b90506143d5816b033b2e3c9fd0803ce8000000615e1b565b8211156143f55760405163e80fa38160e01b815260040160405180910390fd5b6143ff8183615d83565b9998505050505050505050565b6000613bef83836147e7565b600081815260018301602052604081205461445f575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556114d2565b5060006114d2565b600082600001828154811061447e5761447e615f22565b9060005260206000200154905092915050565b61449a896148da565b6144e65760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610c03565b6144ef886148da565b61453b5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610c03565b614544836148da565b6145905760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610c03565b614599826148da565b6145e55760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610c03565b6145f1878a88876149b3565b61463d5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610c03565b60006146498a87614ad6565b9050600061465c898b878b868989614b3a565b9050600061466d838d8d8a86614c5a565b9050808a146146ae5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c03565b505050505050505050505050565b60004661a4b18114806146d1575062066eed81145b1561471057606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561404157600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093670100000000000000900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561477a57600080fd5b505afa15801561478e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147b29190615873565b5094509092508491505080156147d657506147cd8242615e1b565b8463ffffffff16105b15613c3e5750601154949350505050565b600081815260018301602052604081205480156148d057600061480b600183615e1b565b855490915060009061481f90600190615e1b565b905081811461488457600086600001828154811061483f5761483f615f22565b906000526020600020015490508087600001848154811061486257614862615f22565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061489557614895615f0c565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506114d2565b60009150506114d2565b80516000906401000003d019116149335760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0191161498c5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610c03565b60208201516401000003d0199080096149ac8360005b6020020151614c9a565b1492915050565b60006001600160a01b0382166149f95760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610c03565b602084015160009060011615614a1057601c614a13565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa158015614aae573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614ade6151c8565b614b0b60018484604051602001614af793929190615a18565b604051602081830303815290604052614cbe565b90505b614b17816148da565b6114d2578051604080516020810192909252614b339101614af7565b9050614b0e565b614b426151c8565b825186516401000003d0199081900691061415614ba15760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610c03565b614bac878988614d0c565b614bf85760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610c03565b614c03848685614d0c565b614c4f5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610c03565b614312868484614e34565b600060028686868587604051602001614c78969594939291906159b9565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614cc66151c8565b614ccf82614efb565b8152614ce4614cdf8260006149a2565b614f36565b6020820181905260029006600114156125e8576020810180516401000003d019039052919050565b600082614d495760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610c03565b83516020850151600090614d5f90600290615ecc565b15614d6b57601c614d6e565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614de0573d6000803e3d6000fd5b505050602060405103519050600086604051602001614dff91906159a7565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614e3c6151c8565b835160208086015185519186015160009384938493614e5d93909190614f56565b919450925090506401000003d019858209600114614ebd5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610c03565b60405180604001604052806401000003d01980614edc57614edc615ef6565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d01981106125e857604080516020808201939093528151808203840181529082019091528051910120614f03565b60006114d2826002614f4f6401000003d0196001615d83565b901c615036565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614f96838385856150d8565b9098509050614fa788828e886150fc565b9098509050614fb888828c876150fc565b90985090506000614fcb8d878b856150fc565b9098509050614fdc888286866150d8565b9098509050614fed88828e896150fc565b9098509050818114615022576401000003d019818a0998506401000003d01982890997506401000003d0198183099650615026565b8196505b5050505050509450945094915050565b6000806150416151e6565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152615073615204565b60208160c0846005600019fa9250826150ce5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610c03565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b82805482825590600052602060002090810192821561519a579160200282015b8281111561519a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615165565b506151a6929150615222565b5090565b5080546000825590600052602060002090810190610c0c9190615222565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156151a65760008155600101615223565b80356125e881615f4e565b80604081018310156114d257600080fd5b600082601f83011261526457600080fd5b61526c615cec565b80838560408601111561527e57600080fd5b60005b60028110156152a0578135845260209384019390910190600101615281565b509095945050505050565b600082601f8301126152bc57600080fd5b81356001600160401b03808211156152d6576152d6615f38565b604051601f8301601f19908116603f011681019082821181831017156152fe576152fe615f38565b8160405283815286602085880101111561531757600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561534957600080fd5b615351615d14565b905081356001600160401b03808216821461536b57600080fd5b81835260208401356020840152615384604085016153ea565b6040840152615395606085016153ea565b60608401526153a660808501615237565b608084015260a08401359150808211156153bf57600080fd5b506153cc848285016152ab565b60a08301525092915050565b803561ffff811681146125e857600080fd5b803563ffffffff811681146125e857600080fd5b805169ffffffffffffffffffff811681146125e857600080fd5b80356001600160601b03811681146125e857600080fd5b60006020828403121561544157600080fd5b8135613bef81615f4e565b6000806040838503121561545f57600080fd5b823561546a81615f4e565b915061547860208401615418565b90509250929050565b6000806040838503121561549457600080fd5b823561549f81615f4e565b915060208301356154af81615f4e565b809150509250929050565b600080606083850312156154cd57600080fd5b82356154d881615f4e565b91506154788460208501615242565b600080600080606085870312156154fd57600080fd5b843561550881615f4e565b93506020850135925060408501356001600160401b038082111561552b57600080fd5b818701915087601f83011261553f57600080fd5b81358181111561554e57600080fd5b88602082850101111561556057600080fd5b95989497505060200194505050565b60006040828403121561558157600080fd5b613bef8383615242565b60006040828403121561559d57600080fd5b613bef8383615253565b6000602082840312156155b957600080fd5b8151613bef81615f63565b6000602082840312156155d657600080fd5b5035919050565b6000602082840312156155ef57600080fd5b5051919050565b60006020828403121561560857600080fd5b604051602081018181106001600160401b038211171561562a5761562a615f38565b604052823561563881615f63565b81529392505050565b6000808284036101c081121561565657600080fd5b6101a08082121561566657600080fd5b61566e615d36565b915061567a8686615253565b82526156898660408701615253565b60208301526080850135604083015260a0850135606083015260c085013560808301526156b860e08601615237565b60a08301526101006156cc87828801615253565b60c08401526156df876101408801615253565b60e0840152610180860135908301529092508301356001600160401b0381111561570857600080fd5b61571485828601615337565b9150509250929050565b60006020828403121561573057600080fd5b81356001600160401b0381111561574657600080fd5b820160c08185031215613bef57600080fd5b60006020828403121561576a57600080fd5b613bef826153d8565b60008060008060008086880360e081121561578d57600080fd5b615796886153d8565b96506157a4602089016153ea565b95506157b2604089016153ea565b94506157c0606089016153ea565b9350608088013592506040609f19820112156157db57600080fd5b506157e4615cec565b6157f060a089016153ea565b81526157fe60c089016153ea565b6020820152809150509295509295509295565b6000806040838503121561582457600080fd5b8235915060208301356154af81615f4e565b6000806040838503121561584957600080fd5b50508035926020909101359150565b60006020828403121561586a57600080fd5b613bef826153ea565b600080600080600060a0868803121561588b57600080fd5b615894866153fe565b94506020860151935060408601519250606086015191506158b7608087016153fe565b90509295509295909350565b600081518084526020808501945080840160005b838110156158fc5781516001600160a01b0316875295820195908201906001016158d7565b509495945050505050565b8060005b6002811015610e6b57815184526020938401939091019060010161590b565b600081518084526020808501945080840160005b838110156158fc5781518752958201959082019060010161593e565b6000815180845260005b8181101561598057602081850181015186830182015201615964565b81811115615992576000602083870101525b50601f01601f19169290920160200192915050565b6159b18183615907565b604001919050565b8681526159c96020820187615907565b6159d66060820186615907565b6159e360a0820185615907565b6159f060e0820184615907565b60609190911b6bffffffffffffffffffffffff19166101208201526101340195945050505050565b838152615a286020820184615907565b606081019190915260800192915050565b604081016114d28284615907565b602081526000613bef602083018461592a565b602081526000613bef602083018461595a565b6020815260ff8251166020820152602082015160408201526001600160a01b0360408301511660608201526000606083015160c06080840152615ab360e08401826158c3565b905060808401516001600160601b0380821660a08601528060a08701511660c086015250508091505092915050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615b3357845183529383019391830191600101615b17565b509098975050505050505050565b82815260608101613bef6020830184615907565b828152604060208201526000613c3e604083018461592a565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261431260c083018461595a565b878152866020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143ff60e083018461595a565b8781526001600160401b0387166020820152856040820152600063ffffffff80871660608401528086166080840152506001600160a01b03841660a083015260e060c08301526143ff60e083018461595a565b60006001600160601b0380881683528087166020840152506001600160401b03851660408301526001600160a01b038416606083015260a06080830152615c9460a08301846158c3565b979650505050505050565b6000808335601e19843603018112615cb657600080fd5b8301803591506001600160401b03821115615cd057600080fd5b602001915036819003821315615ce557600080fd5b9250929050565b604080519081016001600160401b0381118282101715615d0e57615d0e615f38565b60405290565b60405160c081016001600160401b0381118282101715615d0e57615d0e615f38565b60405161012081016001600160401b0381118282101715615d0e57615d0e615f38565b60008085851115615d6957600080fd5b83861115615d7657600080fd5b5050820193919092039150565b60008219821115615d9657615d96615ee0565b500190565b60006001600160401b03808316818516808303821115615dbd57615dbd615ee0565b01949350505050565b60006001600160601b03808316818516808303821115615dbd57615dbd615ee0565b600082615df757615df7615ef6565b500490565b6000816000190483118215151615615e1657615e16615ee0565b500290565b600082821015615e2d57615e2d615ee0565b500390565b60006001600160601b0383811690831681811015615e5257615e52615ee0565b039392505050565b6001600160e01b03198135818116916004851015615e825780818660040360031b1b83161692505b505092915050565b6000600019821415615e9e57615e9e615ee0565b5060010190565b60006001600160401b0380831681811415615ec257615ec2615ee0565b6001019392505050565b600082615edb57615edb615ef6565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610c0c57600080fd5b8015158114610c0c57600080fdfea164736f6c6343000806000a", + Bin: "0x60a06040523480156200001157600080fd5b506040516200615d3803806200615d833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f82620001db60003960008181610566015261384f0152615f826000f3fe60806040526004361061023c5760003560e01c806379ba50971161012f578063b08c8795116100b1578063b08c87951461076d578063b2a7cac51461078d578063bec4c08c146107ad578063caf70c4a146107cd578063cb631797146107ed578063d98e620e1461080d578063da2f26101461082d578063dac83d2914610863578063dc311dd314610883578063e72f6e30146108b4578063ee9d2d38146108d4578063f2fde38b1461090157600080fd5b806379ba50971461060d5780638402595e1461062257806386fe91c7146106425780638da5cb5b1461066257806395b55cfc146106805780639b1c385e146106935780639d40a6fd146106b3578063a21a23e4146106eb578063a4c0ed3614610700578063aa433aff14610720578063aefb212f1461074057600080fd5b8063330987b3116101c3578063330987b314610444578063405b84fa1461046457806340d6bb821461048457806341af6c87146104af5780635d06b4ab146104df57806364d51a2a146104ff578063659827441461051457806366316d8d14610534578063689c4517146105545780636b6feccc146105885780636f64f03f146105cd57806372e9d565146105ed57600080fd5b80620122911461024157806304104edb1461026e578063043bd6ae14610290578063088070f5146102b457806308821d58146103345780630ae095401461035457806315c48b841461037457806318e3dd271461039c5780631b6b6d23146103db5780632949265714610408578063294daa4914610428575b600080fd5b34801561024d57600080fd5b50610256610921565b60405161026593929190615a61565b60405180910390f35b34801561027a57600080fd5b5061028e61028936600461533c565b61099d565b005b34801561029c57600080fd5b506102a660115481565b604051908152602001610265565b3480156102c057600080fd5b50600d546102fc9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610265565b34801561034057600080fd5b5061028e61034f36600461547c565b610b53565b34801561036057600080fd5b5061028e61036f36600461571e565b610ce7565b34801561038057600080fd5b5061038960c881565b60405161ffff9091168152602001610265565b3480156103a857600080fd5b50600a546103c390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610265565b3480156103e757600080fd5b506002546103fb906001600160a01b031681565b604051610265919061594f565b34801561041457600080fd5b5061028e610423366004615359565b610dac565b34801561043457600080fd5b5060405160018152602001610265565b34801561045057600080fd5b506103c361045f36600461554e565b610f29565b34801561047057600080fd5b5061028e61047f36600461571e565b61140d565b34801561049057600080fd5b5061049a6101f481565b60405163ffffffff9091168152602001610265565b3480156104bb57600080fd5b506104cf6104ca3660046154d1565b6117f8565b6040519015158152602001610265565b3480156104eb57600080fd5b5061028e6104fa36600461533c565b611999565b34801561050b57600080fd5b50610389606481565b34801561052057600080fd5b5061028e61052f36600461538e565b611a50565b34801561054057600080fd5b5061028e61054f366004615359565b611ab0565b34801561056057600080fd5b506103fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059457600080fd5b506012546105b09063ffffffff80821691600160201b90041682565b6040805163ffffffff938416815292909116602083015201610265565b3480156105d957600080fd5b5061028e6105e83660046153c7565b611c78565b3480156105f957600080fd5b506003546103fb906001600160a01b031681565b34801561061957600080fd5b5061028e611d77565b34801561062e57600080fd5b5061028e61063d36600461533c565b611e21565b34801561064e57600080fd5b50600a546103c3906001600160601b031681565b34801561066e57600080fd5b506000546001600160a01b03166103fb565b61028e61068e3660046154d1565b611f33565b34801561069f57600080fd5b506102a66106ae36600461562b565b61207a565b3480156106bf57600080fd5b506007546106d3906001600160401b031681565b6040516001600160401b039091168152602001610265565b3480156106f757600080fd5b506102a661240c565b34801561070c57600080fd5b5061028e61071b3660046153f4565b61265a565b34801561072c57600080fd5b5061028e61073b3660046154d1565b6127fa565b34801561074c57600080fd5b5061076061075b366004615743565b61285a565b60405161026591906159c6565b34801561077957600080fd5b5061028e610788366004615680565b61295b565b34801561079957600080fd5b5061028e6107a83660046154d1565b612ade565b3480156107b957600080fd5b5061028e6107c836600461571e565b612c02565b3480156107d957600080fd5b506102a66107e8366004615498565b612d99565b3480156107f957600080fd5b5061028e61080836600461571e565b612dc9565b34801561081957600080fd5b506102a66108283660046154d1565b6130b6565b34801561083957600080fd5b506103fb6108483660046154d1565b600e602052600090815260409020546001600160a01b031681565b34801561086f57600080fd5b5061028e61087e36600461571e565b6130d7565b34801561088f57600080fd5b506108a361089e3660046154d1565b6131e7565b604051610265959493929190615be3565b3480156108c057600080fd5b5061028e6108cf36600461533c565b6132e2565b3480156108e057600080fd5b506102a66108ef3660046154d1565b60106020526000908152604090205481565b34801561090d57600080fd5b5061028e61091c36600461533c565b6134c3565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561098b57602002820191906000526020600020905b815481526020019060010190808311610977575b50505050509050925092509250909192565b6109a56134d4565b60135460005b81811015610b2b57826001600160a01b0316601382815481106109d0576109d0615ede565b6000918252602090912001546001600160a01b03161415610b195760136109f8600184615dab565b81548110610a0857610a08615ede565b600091825260209091200154601380546001600160a01b039092169183908110610a3457610a34615ede565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610a6b600185615dab565b81548110610a7b57610a7b615ede565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610aba57610aba615ec8565b600082815260209020810160001990810180546001600160a01b03191690550190556040517ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3790610b0c90859061594f565b60405180910390a1505050565b80610b2381615e46565b9150506109ab565b5081604051635428d44960e01b8152600401610b47919061594f565b60405180910390fd5b50565b610b5b6134d4565b604080518082018252600091610b8a919084906002908390839080828437600092019190915250612d99915050565b6000818152600e60205260409020549091506001600160a01b031680610bc657604051631dfd6e1360e21b815260048101839052602401610b47565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610c9e5782600f8281548110610c0157610c01615ede565b90600052602060002001541415610c8c57600f805460009190610c2690600190615dab565b81548110610c3657610c36615ede565b9060005260206000200154905080600f8381548110610c5757610c57615ede565b600091825260209091200155600f805480610c7457610c74615ec8565b60019003818190600052602060002001600090559055505b80610c9681615e46565b915050610be3565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610cda91815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610d1f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610d4a5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615610d755760405163769dd35360e11b815260040160405180910390fd5b610d7e846117f8565b15610d9c57604051631685ecdd60e31b815260040160405180910390fd5b610da68484613529565b50505050565b600d54600160301b900460ff1615610dd75760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b0380831691161015610e1357604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290610e3b9084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610e839190615dc2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610efd576040519150601f19603f3d011682016040523d82523d6000602084013e610f02565b606091505b5050905080610f245760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff1615610f575760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610f6885856136e4565b90506000846060015163ffffffff166001600160401b03811115610f8e57610f8e615ef4565b604051908082528060200260200182016040528015610fb7578160200160208202803683370190505b50905060005b856060015163ffffffff1681101561103757826040015181604051602001610fef929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c82828151811061101a5761101a615ede565b60209081029190910101528061102f81615e46565b915050610fbd565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b9161106f91908690602401615aeb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805460ff60301b1916600160301b1790559088015160808901519192506000916110d49163ffffffff169084613971565b600d805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611114816001615d34565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a0151805161116190600190615dab565b8151811061117157611171615ede565b602091010151600d5460f89190911c60011491506000906111a2908a90600160581b900463ffffffff163a856139bf565b905081156112ab576020808c01516000908152600690915260409020546001600160601b03808316600160601b9092041610156111f257604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611229908490600160601b90046001600160601b0316615dc2565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c90915281208054859450909261128291859116615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550611397565b6020808c01516000908152600690915260409020546001600160601b03808316911610156112ec57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906113199084906001600160601b0316615dc2565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b90915281208054859450909261137291859116615d56565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a6040015184886040516113f4939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156114385760405163769dd35360e11b815260040160405180910390fd5b61144181613a0e565b6114605780604051635428d44960e01b8152600401610b47919061594f565b60008060008061146f866131e7565b945094505093509350336001600160a01b0316826001600160a01b0316146114d25760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610b47565b6114db866117f8565b156115215760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610b47565b60006040518060c00160405280611536600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161158a91906159ec565b60405160208183030381529060405290506115a488613a78565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906115dd9085906004016159d9565b6000604051808303818588803b1580156115f657600080fd5b505af115801561160a573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611633905057506001600160601b03861615155b156116fd5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061166a908a908a90600401615996565b602060405180830381600087803b15801561168457600080fd5b505af1158015611698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bc91906154b4565b6116fd5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610b47565b600d805460ff60301b1916600160301b17905560005b83518110156117a65783818151811061172e5761172e615ede565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b8152600401611761919061594f565b600060405180830381600087803b15801561177b57600080fd5b505af115801561178f573d6000803e3d6000fd5b50505050808061179e90615e46565b915050611713565b50600d805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906117e69089908b90615963565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561188257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611864575b505050505081525050905060005b81604001515181101561198f5760005b600f5481101561197c576000611945600f83815481106118c2576118c2615ede565b9060005260206000200154856040015185815181106118e3576118e3615ede565b602002602001015188600460008960400151898151811061190657611906615ede565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613cc6565b50600081815260106020526040902054909150156119695750600195945050505050565b508061197481615e46565b9150506118a0565b508061198781615e46565b915050611890565b5060009392505050565b6119a16134d4565b6119aa81613a0e565b156119ca578060405163ac8a27ef60e01b8152600401610b47919061594f565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611a4590839061594f565b60405180910390a150565b611a586134d4565b6002546001600160a01b031615611a8257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff1615611adb5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611b045760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611b4057604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611b689084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611bb09190615dc2565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611c059085908590600401615996565b602060405180830381600087803b158015611c1f57600080fd5b505af1158015611c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5791906154b4565b611c7457604051631e9acf1760e31b815260040160405180910390fd5b5050565b611c806134d4565b604080518082018252600091611caf919084906002908390839080828437600092019190915250612d99915050565b6000818152600e60205260409020549091506001600160a01b031615611ceb57604051634a0b8fa760e01b815260048101829052602401610b47565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610cda565b6001546001600160a01b03163314611dca5760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610b47565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611e296134d4565b600a544790600160601b90046001600160601b031681811115611e69576040516354ced18160e11b81526004810182905260248101839052604401610b47565b81811015610f24576000611e7d8284615dab565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611ecc576040519150601f19603f3d011682016040523d82523d6000602084013e611ed1565b606091505b5050905080611ef35760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611f24929190615963565b60405180910390a15050505050565b600d54600160301b900460ff1615611f5e5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611f9357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611fc28385615d56565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b031661200a9190615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e90282348461205d9190615d1c565b604080519283526020830191909152015b60405180910390a25050565b600d54600090600160301b900460ff16156120a85760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b03166120e357604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612130578260200135336040516379bfd40160e01b8152600401610b47929190615ac0565b600d5461ffff166121476060850160408601615665565b61ffff16108061216a575060c86121646060850160408601615665565b61ffff16115b156121b05761217f6060840160408501615665565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610b47565b600d5462010000900463ffffffff166121cf6080850160608601615765565b63ffffffff16111561221f576121eb6080840160608501615765565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610b47565b6101f461223260a0850160808601615765565b63ffffffff1611156122785761224e60a0840160808501615765565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610b47565b6000612285826001615d34565b905060008061229b863533602089013586613cc6565b909250905060006122b76122b260a0890189615c38565b613d3f565b905060006122c482613dbc565b9050836122cf613e2d565b60208a01356122e460808c0160608d01615765565b6122f460a08d0160808e01615765565b338660405160200161230c9796959493929190615b43565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d60400160208101906123839190615665565b8e60600160208101906123969190615765565b8f60800160208101906123a99190615765565b896040516123bc96959493929190615b04565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff161561243a5760405163769dd35360e11b815260040160405180910390fd5b600033612448600143615dab565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b039091169060006124c283615e61565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561250157612501615ef4565b60405190808252806020026020018201604052801561252a578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361260b9260028501920190615052565b5061261b91506008905083613ebd565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161264c919061594f565b60405180910390a250905090565b600d54600160301b900460ff16156126855760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b031633146126b0576040516344b0e3c360e01b815260040160405180910390fd5b602081146126d157604051638129bbcd60e01b815260040160405180910390fd5b60006126df828401846154d1565b6000818152600560205260409020549091506001600160a01b031661271757604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061273e8385615d56565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166127869190615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846127d99190615d1c565b604080519283526020830191909152015b60405180910390a2505050505050565b6128026134d4565b6000818152600560205260409020546001600160a01b031661283757604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610b509082906001600160a01b0316613529565b606060006128686008613ec9565b905080841061288a57604051631390f2a160e01b815260040160405180910390fd5b60006128968486615d1c565b9050818111806128a4575083155b6128ae57806128b0565b815b905060006128be8683615dab565b6001600160401b038111156128d5576128d5615ef4565b6040519080825280602002602001820160405280156128fe578160200160208202803683370190505b50905060005b81518110156129515761292261291a8883615d1c565b600890613ed3565b82828151811061293457612934615ede565b60209081029190910101528061294981615e46565b915050612904565b5095945050505050565b6129636134d4565b60c861ffff8716111561299d5760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610b47565b600082136129c1576040516321ea67b360e11b815260048101839052602401610b47565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff191688176201000087021768ffffffffffffffffff60301b1916600160381b850263ffffffff60581b191617600160581b83021790558a51601280548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612b095760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612b3e57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612b95576000818152600560205260409081902060010154905163d084e97560e01b8152610b47916001600160a01b03169060040161594f565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c93869161206e91859161597c565b60008281526005602052604090205482906001600160a01b031680612c3a57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612c655780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615612c905760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612cc3576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612cfa57610da6565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e190612d8b90869061594f565b60405180910390a250505050565b600081604051602001612dac91906159b8565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612e0157604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612e2c5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615612e575760405163769dd35360e11b815260040160405180910390fd5b612e60846117f8565b15612e7e57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612ecc5783836040516379bfd40160e01b8152600401610b47929190615ac0565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612f2f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f11575b50505050509050600060018251612f469190615dab565b905060005b825181101561305257856001600160a01b0316838281518110612f7057612f70615ede565b60200260200101516001600160a01b03161415613040576000838381518110612f9b57612f9b615ede565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612fcd57612fcd615ede565b600091825260208083209190910180546001600160a01b0319166001600160a01b03949094169390931790925589815260059091526040902060020180548061301857613018615ec8565b600082815260209020810160001990810180546001600160a01b031916905501905550613052565b8061304a81615e46565b915050612f4b565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906127ea90889061594f565b600f81815481106130c657600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03168061310f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461313a5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff16156131655760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610da6576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612d8b903390879061597c565b6000818152600560205260408120548190819081906060906001600160a01b031661322557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156132c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132aa575b505050505090509450945094509450945091939590929450565b6132ea6134d4565b6002546001600160a01b03166133135760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a082319061334490309060040161594f565b60206040518083038186803b15801561335c57600080fd5b505afa158015613370573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339491906154ea565b600a549091506001600160601b0316818111156133ce576040516354ced18160e11b81526004810182905260248101839052604401610b47565b81811015610f245760006133e28284615dab565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb906134159087908590600401615963565b602060405180830381600087803b15801561342f57600080fd5b505af1158015613443573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346791906154b4565b61348457604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b43660084826040516134b5929190615963565b60405180910390a150505050565b6134cb6134d4565b610b5081613edf565b6000546001600160a01b031633146135275760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610b47565b565b60008061353584613a78565b60025491935091506001600160a01b03161580159061355c57506001600160601b03821615155b1561360b5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061359c9086906001600160601b03871690600401615963565b602060405180830381600087803b1580156135b657600080fd5b505af11580156135ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ee91906154b4565b61360b57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613661576040519150601f19603f3d011682016040523d82523d6000602084013e613666565b606091505b50509050806136885760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006137108460000151612d99565b6000818152600e60205260409020549091506001600160a01b03168061374c57604051631dfd6e1360e21b815260048101839052602401610b47565b600082866080015160405160200161376e929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806137b457604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516137e3978a979096959101615b8f565b6040516020818303038152906040528051906020012081146138185760405163354a450b60e21b815260040160405180910390fd5b60006138278760000151613f83565b9050806138ff578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561389957600080fd5b505afa1580156138ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d191906154ea565b9050806138ff57865160405163175dadad60e01b81526001600160401b039091166004820152602401610b47565b6000886080015182604051602001613921929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006139488a83614065565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a61138881101561398357600080fd5b61138881039050846040820482031161399b57600080fd5b50823b6139a757600080fd5b60008083516020850160008789f190505b9392505050565b600081156139ec576012546139e59086908690600160201b900463ffffffff16866140d0565b9050613a06565b601254613a03908690869063ffffffff1686614172565b90505b949350505050565b6000805b601354811015613a6f57826001600160a01b031660138281548110613a3957613a39615ede565b6000918252602090912001546001600160a01b03161415613a5d5750600192915050565b80613a6781615e46565b915050613a12565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613b0457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613ae6575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613be0576004600084604001518381518110613b9057613b90615ede565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b031916905580613bd881615e46565b915050613b69565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613c1860028301826150b7565b5050600085815260066020526040812055613c34600886614298565b50600a8054859190600090613c539084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613c9b9190615dc2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b6040805160208082018790526001600160a01b03959095168183015260608101939093526001600160401b03919091166080808401919091528151808403909101815260a08301825280519084012060c083019490945260e0808301859052815180840390910181526101009092019052805191012091565b60408051602081019091526000815281613d685750604080516020810190915260008152611407565b63125fa26760e31b613d7a8385615dea565b6001600160e01b03191614613da257604051632923fee760e11b815260040160405180910390fd5b613daf8260048186615cf2565b8101906139b89190615503565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613df591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613e39816142a4565b15613eb65760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7857600080fd5b505afa158015613e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613eb091906154ea565b91505090565b4391505090565b60006139b883836142c7565b6000611407825490565b60006139b88383614316565b6001600160a01b038116331415613f325760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610b47565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613f8f816142a4565b1561405657610100836001600160401b0316613fa9613e2d565b613fb39190615dab565b1180613fcf5750613fc2613e2d565b836001600160401b031610155b15613fdd5750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a82906024015b60206040518083038186803b15801561401e57600080fd5b505afa158015614032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b891906154ea565b50506001600160401b03164090565b60006140998360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614340565b600383602001516040516020016140b1929190615ad7565b60408051601f1981840301815291905280516020909101209392505050565b6000806141136000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061455c92505050565b905060005a6141228888615d1c565b61412c9190615dab565b6141369085615d8c565b9050600061414f63ffffffff871664e8d4a51000615d8c565b90508261415c8284615d1c565b6141669190615d1c565b98975050505050505050565b60008061417d614621565b9050600081136141a3576040516321ea67b360e11b815260048101829052602401610b47565b60006141e56000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061455c92505050565b9050600082825a6141f68b8b615d1c565b6142009190615dab565b61420a9088615d8c565b6142149190615d1c565b61422690670de0b6b3a7640000615d8c565b6142309190615d78565b9050600061424963ffffffff881664e8d4a51000615d8c565b9050614261816b033b2e3c9fd0803ce8000000615dab565b8211156142815760405163e80fa38160e01b815260040160405180910390fd5b61428b8183615d1c565b9998505050505050505050565b60006139b883836146ec565b600061a4b18214806142b8575062066eed82145b8061140757505062066eee1490565b600081815260018301602052604081205461430e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611407565b506000611407565b600082600001828154811061432d5761432d615ede565b9060005260206000200154905092915050565b614349896147df565b6143925760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610b47565b61439b886147df565b6143df5760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610b47565b6143e8836147df565b6144345760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610b47565b61443d826147df565b6144895760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610b47565b614495878a88876148a2565b6144dd5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610b47565b60006144e98a876149c5565b905060006144fc898b878b868989614a29565b9050600061450d838d8d8a86614b3c565b9050808a1461454e5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b47565b505050505050505050505050565b600046614568816142a4565b156145a757606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561401e57600080fd5b6145b081614b7c565b15613a6f57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615f2e604891396040516020016145f69291906158a5565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161400691906159d9565b600d5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561467f57600080fd5b505afa158015614693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146b79190615780565b5094509092508491505080156146db57506146d28242615dab565b8463ffffffff16105b15613a065750601154949350505050565b600081815260018301602052604081205480156147d5576000614710600183615dab565b855490915060009061472490600190615dab565b905081811461478957600086600001828154811061474457614744615ede565b906000526020600020015490508087600001848154811061476757614767615ede565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061479a5761479a615ec8565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611407565b6000915050611407565b80516000906401000003d0191161482d5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610b47565b60208201516401000003d0191161487b5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610b47565b60208201516401000003d01990800961489b8360005b6020020151614bb6565b1492915050565b60006001600160a01b0382166148e85760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610b47565b6020840151600090600116156148ff57601c614902565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561499d573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b6149cd6150d5565b6149fa600184846040516020016149e69392919061592e565b604051602081830303815290604052614bda565b90505b614a06816147df565b611407578051604080516020810192909252614a2291016149e6565b90506149fd565b614a316150d5565b825186516401000003d0199081900691061415614a905760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610b47565b614a9b878988614c28565b614ae05760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610b47565b614aeb848685614c28565b614b315760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610b47565b614166868484614d50565b600060028686868587604051602001614b5a969594939291906158d4565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a821480614b8e57506101a482145b80614b9b575062aa37dc82145b80614ba7575061210582145b8061140757505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614be26150d5565b614beb82614e13565b8152614c00614bfb826000614891565b614e4e565b602082018190526002900660011415612407576020810180516401000003d019039052919050565b600082614c655760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610b47565b83516020850151600090614c7b90600290615e88565b15614c8757601c614c8a565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614cfc573d6000803e3d6000fd5b505050602060405103519050600086604051602001614d1b9190615893565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614d586150d5565b835160208086015185519186015160009384938493614d7993909190614e6e565b919450925090506401000003d019858209600114614dd55760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610b47565b60405180604001604052806401000003d01980614df457614df4615eb2565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061240757604080516020808201939093528151808203840181529082019091528051910120614e1b565b6000611407826002614e676401000003d0196001615d1c565b901c614f4e565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614eae83838585614fe5565b9098509050614ebf88828e88615009565b9098509050614ed088828c87615009565b90985090506000614ee38d878b85615009565b9098509050614ef488828686614fe5565b9098509050614f0588828e89615009565b9098509050818114614f3a576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614f3e565b8196505b5050505050509450945094915050565b600080614f596150f3565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614f8b615111565b60208160c0846005600019fa925082614fdb5760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610b47565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b8280548282559060005260206000209081019282156150a7579160200282015b828111156150a757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615072565b506150b392915061512f565b5090565b5080546000825590600052602060002090810190610b50919061512f565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156150b35760008155600101615130565b803561240781615f0a565b806040810183101561140757600080fd5b600082601f83011261517157600080fd5b615179615c85565b80838560408601111561518b57600080fd5b60005b60028110156151ad57813584526020938401939091019060010161518e565b509095945050505050565b600082601f8301126151c957600080fd5b81356001600160401b03808211156151e3576151e3615ef4565b604051601f8301601f19908116603f0116810190828211818310171561520b5761520b615ef4565b8160405283815286602085880101111561522457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561525657600080fd5b61525e615cad565b905081356001600160401b03808216821461527857600080fd5b81835260208401356020840152615291604085016152f7565b60408401526152a2606085016152f7565b60608401526152b360808501615144565b608084015260a08401359150808211156152cc57600080fd5b506152d9848285016151b8565b60a08301525092915050565b803561ffff8116811461240757600080fd5b803563ffffffff8116811461240757600080fd5b805169ffffffffffffffffffff8116811461240757600080fd5b80356001600160601b038116811461240757600080fd5b60006020828403121561534e57600080fd5b81356139b881615f0a565b6000806040838503121561536c57600080fd5b823561537781615f0a565b915061538560208401615325565b90509250929050565b600080604083850312156153a157600080fd5b82356153ac81615f0a565b915060208301356153bc81615f0a565b809150509250929050565b600080606083850312156153da57600080fd5b82356153e581615f0a565b9150615385846020850161514f565b6000806000806060858703121561540a57600080fd5b843561541581615f0a565b93506020850135925060408501356001600160401b038082111561543857600080fd5b818701915087601f83011261544c57600080fd5b81358181111561545b57600080fd5b88602082850101111561546d57600080fd5b95989497505060200194505050565b60006040828403121561548e57600080fd5b6139b8838361514f565b6000604082840312156154aa57600080fd5b6139b88383615160565b6000602082840312156154c657600080fd5b81516139b881615f1f565b6000602082840312156154e357600080fd5b5035919050565b6000602082840312156154fc57600080fd5b5051919050565b60006020828403121561551557600080fd5b604051602081018181106001600160401b038211171561553757615537615ef4565b604052823561554581615f1f565b81529392505050565b6000808284036101c081121561556357600080fd5b6101a08082121561557357600080fd5b61557b615ccf565b91506155878686615160565b82526155968660408701615160565b60208301526080850135604083015260a0850135606083015260c085013560808301526155c560e08601615144565b60a08301526101006155d987828801615160565b60c08401526155ec876101408801615160565b60e0840152610180860135908301529092508301356001600160401b0381111561561557600080fd5b61562185828601615244565b9150509250929050565b60006020828403121561563d57600080fd5b81356001600160401b0381111561565357600080fd5b820160c081850312156139b857600080fd5b60006020828403121561567757600080fd5b6139b8826152e5565b60008060008060008086880360e081121561569a57600080fd5b6156a3886152e5565b96506156b1602089016152f7565b95506156bf604089016152f7565b94506156cd606089016152f7565b9350608088013592506040609f19820112156156e857600080fd5b506156f1615c85565b6156fd60a089016152f7565b815261570b60c089016152f7565b6020820152809150509295509295509295565b6000806040838503121561573157600080fd5b8235915060208301356153bc81615f0a565b6000806040838503121561575657600080fd5b50508035926020909101359150565b60006020828403121561577757600080fd5b6139b8826152f7565b600080600080600060a0868803121561579857600080fd5b6157a18661530b565b94506020860151935060408601519250606086015191506157c46080870161530b565b90509295509295909350565b600081518084526020808501945080840160005b838110156158095781516001600160a01b0316875295820195908201906001016157e4565b509495945050505050565b8060005b6002811015610da6578151845260209384019390910190600101615818565b600081518084526020808501945080840160005b838110156158095781518752958201959082019060010161584b565b6000815180845261587f816020860160208601615e1a565b601f01601f19169290920160200192915050565b61589d8183615814565b604001919050565b600083516158b7818460208801615e1a565b8351908301906158cb818360208801615e1a565b01949350505050565b8681526158e46020820187615814565b6158f16060820186615814565b6158fe60a0820185615814565b61590b60e0820184615814565b60609190911b6001600160601b0319166101208201526101340195945050505050565b83815261593e6020820184615814565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b604081016114078284615814565b6020815260006139b86020830184615837565b6020815260006139b86020830184615867565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c06080840152615a3160e08401826157d0565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615ab257845183529383019391830191600101615a96565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016139b86020830184615814565b828152604060208201526000613a066040830184615837565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261416660c0830184615867565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061428b90830184615867565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061428b90830184615867565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615c2d908301846157d0565b979650505050505050565b6000808335601e19843603018112615c4f57600080fd5b8301803591506001600160401b03821115615c6957600080fd5b602001915036819003821315615c7e57600080fd5b9250929050565b604080519081016001600160401b0381118282101715615ca757615ca7615ef4565b60405290565b60405160c081016001600160401b0381118282101715615ca757615ca7615ef4565b60405161012081016001600160401b0381118282101715615ca757615ca7615ef4565b60008085851115615d0257600080fd5b83861115615d0f57600080fd5b5050820193919092039150565b60008219821115615d2f57615d2f615e9c565b500190565b60006001600160401b038083168185168083038211156158cb576158cb615e9c565b60006001600160601b038281168482168083038211156158cb576158cb615e9c565b600082615d8757615d87615eb2565b500490565b6000816000190483118215151615615da657615da6615e9c565b500290565b600082821015615dbd57615dbd615e9c565b500390565b60006001600160601b0383811690831681811015615de257615de2615e9c565b039392505050565b6001600160e01b03198135818116916004851015615e125780818660040360031b1b83161692505b505092915050565b60005b83811015615e35578181015183820152602001615e1d565b83811115610da65750506000910152565b6000600019821415615e5a57615e5a615e9c565b5060010190565b60006001600160401b0380831681811415615e7e57615e7e615e9c565b6001019392505050565b600082615e9757615e97615eb2565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610b5057600080fd5b8015158114610b5057600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var VRFCoordinatorV25ABI = VRFCoordinatorV25MetaData.ABI diff --git a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go index eb11e58ceb2..93d50b72dd5 100644 --- a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go @@ -32,7 +32,7 @@ var ( var VRFV2LoadTestWithMetricsMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c0604052600060045560006005556103e760065534801561002057600080fd5b506040516110f33803806110f383398101604081905261003f91610199565b6001600160601b0319606082901b1660805233806000816100a75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100d7576100d7816100ef565b50505060601b6001600160601b03191660a0526101c9565b6001600160a01b0381163314156101485760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161009e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ab57600080fd5b81516001600160a01b03811681146101c257600080fd5b9392505050565b60805160601c60a05160601c610ef16102026000396000818161014301526103da0152600081816102b7015261031f0152610ef16000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806379ba509711610097578063d826f88f11610066578063d826f88f1461023f578063d8a4676f1461025e578063dc1670db14610283578063f2fde38b1461028c57600080fd5b806379ba5097146101a55780638da5cb5b146101ad578063a168fa89146101cb578063b1e217491461023657600080fd5b80633b2bcbf1116100d35780633b2bcbf11461013e578063557d2e921461018a578063737144bc1461019357806374dba1241461019c57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360055481565b6040519081526020015b60405180910390f35b610129610124366004610bad565b61029f565b005b610129610139366004610c9c565b61035f565b6101657f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b61010360035481565b61010360045481565b61010360065481565b610129610577565b60005473ffffffffffffffffffffffffffffffffffffffff16610165565b61020c6101d9366004610b7b565b6009602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360075481565b6101296000600481905560058190556103e76006556003819055600255565b61027161026c366004610b7b565b610674565b60405161010d96959493929190610d18565b61010360025481565b61012961029a366004610b3e565b610759565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610351576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61035b828261076d565b5050565b610367610894565b60005b8161ffff168161ffff16101561056e576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561043357600080fd5b505af1158015610447573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046b9190610b94565b60078190559050600061047c610917565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526009815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016901515178155905180519495509193909261050a926001850192910190610ab3565b506040820151600282015560608201516003808301919091556080830151600483015560a090920151600590910155805490600061054783610e4d565b9091555050600091825260086020526040909120558061056681610e2b565b91505061036a565b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610348565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000818152600960209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156106f257602002820191906000526020600020905b8154815260200190600101908083116106de575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b610761610894565b61076a816109bd565b50565b6000610777610917565b600084815260086020526040812054919250906107949083610e14565b905060006107a582620f4240610dd7565b90506005548211156107b75760058290555b60065482106107c8576006546107ca565b815b6006556002546107da578061080d565b6002546107e8906001610d84565b816002546004546107f99190610dd7565b6108039190610d84565b61080d9190610d9c565b600455600085815260096020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161085f939290910191870190610ab3565b506000858152600960205260408120426003820155600501849055600280549161088883610e4d565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610348565b565b60004661a4b181148061092c575062066eed81145b156109b657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561097857600080fd5b505afa15801561098c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b09190610b94565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610348565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610aee579160200282015b82811115610aee578251825591602001919060010190610ad3565b50610afa929150610afe565b5090565b5b80821115610afa5760008155600101610aff565b803561ffff81168114610b2557600080fd5b919050565b803563ffffffff81168114610b2557600080fd5b600060208284031215610b5057600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610b7457600080fd5b9392505050565b600060208284031215610b8d57600080fd5b5035919050565b600060208284031215610ba657600080fd5b5051919050565b60008060408385031215610bc057600080fd5b8235915060208084013567ffffffffffffffff80821115610be057600080fd5b818601915086601f830112610bf457600080fd5b813581811115610c0657610c06610eb5565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610c4957610c49610eb5565b604052828152858101935084860182860187018b1015610c6857600080fd5b600095505b83861015610c8b578035855260019590950194938601938601610c6d565b508096505050505050509250929050565b60008060008060008060c08789031215610cb557600080fd5b863567ffffffffffffffff81168114610ccd57600080fd5b9550610cdb60208801610b13565b945060408701359350610cf060608801610b2a565b9250610cfe60808801610b2a565b9150610d0c60a08801610b13565b90509295509295509295565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610d5b57845183529383019391830191600101610d3f565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610d9757610d97610e86565b500190565b600082610dd2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e0f57610e0f610e86565b500290565b600082821015610e2657610e26610e86565b500390565b600061ffff80831681811415610e4357610e43610e86565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610e7f57610e7f610e86565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60c0604052600060045560006005556103e760065534801561002057600080fd5b5060405161111138038061111183398101604081905261003f91610199565b6001600160601b0319606082901b1660805233806000816100a75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100d7576100d7816100ef565b50505060601b6001600160601b03191660a0526101c9565b6001600160a01b0381163314156101485760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161009e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ab57600080fd5b81516001600160a01b03811681146101c257600080fd5b9392505050565b60805160601c60a05160601c610f0f6102026000396000818161014301526103da0152600081816102b7015261031f0152610f0f6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806379ba509711610097578063d826f88f11610066578063d826f88f1461023f578063d8a4676f1461025e578063dc1670db14610283578063f2fde38b1461028c57600080fd5b806379ba5097146101a55780638da5cb5b146101ad578063a168fa89146101cb578063b1e217491461023657600080fd5b80633b2bcbf1116100d35780633b2bcbf11461013e578063557d2e921461018a578063737144bc1461019357806374dba1241461019c57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360055481565b6040519081526020015b60405180910390f35b610129610124366004610bcb565b61029f565b005b610129610139366004610cba565b61035f565b6101657f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b61010360035481565b61010360045481565b61010360065481565b610129610577565b60005473ffffffffffffffffffffffffffffffffffffffff16610165565b61020c6101d9366004610b99565b6009602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360075481565b6101296000600481905560058190556103e76006556003819055600255565b61027161026c366004610b99565b610674565b60405161010d96959493929190610d36565b61010360025481565b61012961029a366004610b5c565b610759565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610351576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61035b828261076d565b5050565b610367610894565b60005b8161ffff168161ffff16101561056e576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561043357600080fd5b505af1158015610447573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046b9190610bb2565b60078190559050600061047c610917565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526009815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016901515178155905180519495509193909261050a926001850192910190610ad1565b506040820151600282015560608201516003808301919091556080830151600483015560a090920151600590910155805490600061054783610e6b565b9091555050600091825260086020526040909120558061056681610e49565b91505061036a565b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610348565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000818152600960209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156106f257602002820191906000526020600020905b8154815260200190600101908083116106de575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b610761610894565b61076a816109b4565b50565b6000610777610917565b600084815260086020526040812054919250906107949083610e32565b905060006107a582620f4240610df5565b90506005548211156107b75760058290555b60065482106107c8576006546107ca565b815b6006556002546107da578061080d565b6002546107e8906001610da2565b816002546004546107f99190610df5565b6108039190610da2565b61080d9190610dba565b600455600085815260096020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161085f939290910191870190610ad1565b506000858152600960205260408120426003820155600501849055600280549161088883610e6b565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610348565b565b60004661092381610aaa565b156109ad57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096f57600080fd5b505afa158015610983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a79190610bb2565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610348565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610abe575062066eed82145b80610acb575062066eee82145b92915050565b828054828255906000526020600020908101928215610b0c579160200282015b82811115610b0c578251825591602001919060010190610af1565b50610b18929150610b1c565b5090565b5b80821115610b185760008155600101610b1d565b803561ffff81168114610b4357600080fd5b919050565b803563ffffffff81168114610b4357600080fd5b600060208284031215610b6e57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610b9257600080fd5b9392505050565b600060208284031215610bab57600080fd5b5035919050565b600060208284031215610bc457600080fd5b5051919050565b60008060408385031215610bde57600080fd5b8235915060208084013567ffffffffffffffff80821115610bfe57600080fd5b818601915086601f830112610c1257600080fd5b813581811115610c2457610c24610ed3565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610c6757610c67610ed3565b604052828152858101935084860182860187018b1015610c8657600080fd5b600095505b83861015610ca9578035855260019590950194938601938601610c8b565b508096505050505050509250929050565b60008060008060008060c08789031215610cd357600080fd5b863567ffffffffffffffff81168114610ceb57600080fd5b9550610cf960208801610b31565b945060408701359350610d0e60608801610b48565b9250610d1c60808801610b48565b9150610d2a60a08801610b31565b90509295509295509295565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610d7957845183529383019391830191600101610d5d565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610db557610db5610ea4565b500190565b600082610df0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e2d57610e2d610ea4565b500290565b600082821015610e4457610e44610ea4565b500390565b600061ffff80831681811415610e6157610e61610ea4565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610e9d57610e9d610ea4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2LoadTestWithMetricsABI = VRFV2LoadTestWithMetricsMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go index b6051bf09ff..64a5cace7f5 100644 --- a/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go +++ b/core/gethwrappers/generated/vrf_malicious_consumer_v2_plus/vrf_malicious_consumer_v2_plus.go @@ -32,7 +32,7 @@ var ( var VRFMaliciousConsumerV2PlusMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001243380380620012438339810160408190526200003491620001cc565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000103565b5050600280546001600160a01b03199081166001600160a01b0394851617909155600580548216958416959095179094555060068054909316911617905562000204565b6001600160a01b0381163314156200015e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001c757600080fd5b919050565b60008060408385031215620001e057600080fd5b620001eb83620001af565b9150620001fb60208401620001af565b90509250929050565b61102f80620002146000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80639eccacf611610081578063f08c5daa1161005b578063f08c5daa146101bd578063f2fde38b146101c6578063f6eaffc8146101d957600080fd5b80639eccacf614610181578063cf62c8ab146101a1578063e89e106a146101b457600080fd5b806379ba5097116100b257806379ba5097146101275780638da5cb5b1461012f5780638ea981171461016e57600080fd5b80631fe543e3146100d957806336bfffed146100ee5780635e3b709f14610101575b600080fd5b6100ec6100e7366004610d03565b6101ec565b005b6100ec6100fc366004610c0b565b610272565b61011461010f366004610cd1565b6103aa565b6040519081526020015b60405180910390f35b6100ec6104a0565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011e565b6100ec61017c366004610bf0565b61059d565b6002546101499073ffffffffffffffffffffffffffffffffffffffff1681565b6100ec6101af366004610da7565b6106a8565b61011460045481565b61011460075481565b6100ec6101d4366004610bf0565b6108ae565b6101146101e7366004610cd1565b6108c2565b60025473ffffffffffffffffffffffffffffffffffffffff163314610264576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61026e82826108e3565b5050565b6008546102db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161025b565b60005b815181101561026e57600554600854835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061032157610321610fc4565b60200260200101516040518363ffffffff1660e01b815260040161036592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561037f57600080fd5b505af1158015610393573d6000803e3d6000fd5b5050505080806103a290610f64565b9150506102de565b60098190556040805160c08101825282815260085460208083019190915260018284018190526207a1206060840152608083015282519081018352600080825260a083019190915260055492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610447908490600401610e8c565b602060405180830381600087803b15801561046157600080fd5b505af1158015610475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610cea565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161025b565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906105dd575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610661573361060260005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161025b565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6008546107e057600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561071957600080fd5b505af115801561072d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107519190610cea565b60088190556005546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505050505b6006546005546008546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361085c93911691869190604401610e40565b602060405180830381600087803b15801561087657600080fd5b505af115801561088a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190610caf565b6108b66109ee565b6108bf81610a71565b50565b600381815481106108d257600080fd5b600091825260209091200154905081565b5a60075580516108fa906003906020840190610b67565b5060048281556040805160c0810182526009548152600854602080830191909152600182840181905262030d4060608401526080830152825190810183526000815260a082015260055491517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff90921691639b1c385e9161099691859101610e8c565b602060405180830381600087803b1580156109b057600080fd5b505af11580156109c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e89190610cea565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161025b565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161025b565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610ba2579160200282015b82811115610ba2578251825591602001919060010190610b87565b50610bae929150610bb2565b5090565b5b80821115610bae5760008155600101610bb3565b803573ffffffffffffffffffffffffffffffffffffffff81168114610beb57600080fd5b919050565b600060208284031215610c0257600080fd5b61049982610bc7565b60006020808385031215610c1e57600080fd5b823567ffffffffffffffff811115610c3557600080fd5b8301601f81018513610c4657600080fd5b8035610c59610c5482610f40565b610ef1565b80828252848201915084840188868560051b8701011115610c7957600080fd5b600094505b83851015610ca357610c8f81610bc7565b835260019490940193918501918501610c7e565b50979650505050505050565b600060208284031215610cc157600080fd5b8151801515811461049957600080fd5b600060208284031215610ce357600080fd5b5035919050565b600060208284031215610cfc57600080fd5b5051919050565b60008060408385031215610d1657600080fd5b8235915060208084013567ffffffffffffffff811115610d3557600080fd5b8401601f81018613610d4657600080fd5b8035610d54610c5482610f40565b80828252848201915084840189868560051b8701011115610d7457600080fd5b600094505b83851015610d97578035835260019490940193918501918501610d79565b5080955050505050509250929050565b600060208284031215610db957600080fd5b81356bffffffffffffffffffffffff8116811461049957600080fd5b6000815180845260005b81811015610dfb57602081850181015186830182015201610ddf565b81811115610e0d576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610e836060830184610dd5565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ee960e0840182610dd5565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f3857610f38610ff3565b604052919050565b600067ffffffffffffffff821115610f5a57610f5a610ff3565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610fbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b5060405162001239380380620012398339810160408190526200003491620001c2565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000f9565b5050600280546001600160a01b039384166001600160a01b0319918216179091556005805494909316931692909217905550620001fa9050565b6001600160a01b038116331415620001545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001bd57600080fd5b919050565b60008060408385031215620001d657600080fd5b620001e183620001a5565b9150620001f160208401620001a5565b90509250929050565b61102f806200020a6000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80639eccacf611610081578063f08c5daa1161005b578063f08c5daa146101bd578063f2fde38b146101c6578063f6eaffc8146101d957600080fd5b80639eccacf614610181578063cf62c8ab146101a1578063e89e106a146101b457600080fd5b806379ba5097116100b257806379ba5097146101275780638da5cb5b1461012f5780638ea981171461016e57600080fd5b80631fe543e3146100d957806336bfffed146100ee5780635e3b709f14610101575b600080fd5b6100ec6100e7366004610d03565b6101ec565b005b6100ec6100fc366004610c0b565b610272565b61011461010f366004610cd1565b6103aa565b6040519081526020015b60405180910390f35b6100ec6104a0565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161011e565b6100ec61017c366004610bf0565b61059d565b6002546101499073ffffffffffffffffffffffffffffffffffffffff1681565b6100ec6101af366004610da7565b6106a8565b61011460045481565b61011460065481565b6100ec6101d4366004610bf0565b6108ae565b6101146101e7366004610cd1565b6108c2565b60025473ffffffffffffffffffffffffffffffffffffffff163314610264576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61026e82826108e3565b5050565b6007546102db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161025b565b60005b815181101561026e57600254600754835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061032157610321610fc4565b60200260200101516040518363ffffffff1660e01b815260040161036592919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b15801561037f57600080fd5b505af1158015610393573d6000803e3d6000fd5b5050505080806103a290610f64565b9150506102de565b60088190556040805160c08101825282815260075460208083019190915260018284018190526207a1206060840152608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610447908490600401610e8c565b602060405180830381600087803b15801561046157600080fd5b505af1158015610475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610cea565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161025b565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906105dd575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15610661573361060260005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161025b565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6007546107e057600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561071957600080fd5b505af115801561072d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107519190610cea565b60078190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505050505b6005546002546007546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361085c93911691869190604401610e40565b602060405180830381600087803b15801561087657600080fd5b505af115801561088a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061026e9190610caf565b6108b66109ee565b6108bf81610a71565b50565b600381815481106108d257600080fd5b600091825260209091200154905081565b5a60065580516108fa906003906020840190610b67565b5060048281556040805160c0810182526008548152600754602080830191909152600182840181905262030d4060608401526080830152825190810183526000815260a082015260025491517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff90921691639b1c385e9161099691859101610e8c565b602060405180830381600087803b1580156109b057600080fd5b505af11580156109c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e89190610cea565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161025b565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161025b565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610ba2579160200282015b82811115610ba2578251825591602001919060010190610b87565b50610bae929150610bb2565b5090565b5b80821115610bae5760008155600101610bb3565b803573ffffffffffffffffffffffffffffffffffffffff81168114610beb57600080fd5b919050565b600060208284031215610c0257600080fd5b61049982610bc7565b60006020808385031215610c1e57600080fd5b823567ffffffffffffffff811115610c3557600080fd5b8301601f81018513610c4657600080fd5b8035610c59610c5482610f40565b610ef1565b80828252848201915084840188868560051b8701011115610c7957600080fd5b600094505b83851015610ca357610c8f81610bc7565b835260019490940193918501918501610c7e565b50979650505050505050565b600060208284031215610cc157600080fd5b8151801515811461049957600080fd5b600060208284031215610ce357600080fd5b5035919050565b600060208284031215610cfc57600080fd5b5051919050565b60008060408385031215610d1657600080fd5b8235915060208084013567ffffffffffffffff811115610d3557600080fd5b8401601f81018613610d4657600080fd5b8035610d54610c5482610f40565b80828252848201915084840189868560051b8701011115610d7457600080fd5b600094505b83851015610d97578035835260019490940193918501918501610d79565b5080955050505050509250929050565b600060208284031215610db957600080fd5b81356bffffffffffffffffffffffff8116811461049957600080fd5b6000815180845260005b81811015610dfb57602081850181015186830182015201610ddf565b81811115610e0d576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610e836060830184610dd5565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ee960e0840182610dd5565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f3857610f38610ff3565b604052919050565b600067ffffffffffffffff821115610f5a57610f5a610ff3565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610fbd577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFMaliciousConsumerV2PlusABI = VRFMaliciousConsumerV2PlusMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go index e815f5491d9..ce42ddb7d6c 100644 --- a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go +++ b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go @@ -32,7 +32,7 @@ var ( var VRFV2OwnerTestConsumerMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"subId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b50604051620013ae380380620013ae8339810160408190526200004491620002bf565b6001600160601b0319606082901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000213565b5050600280546001600160a01b0319166001600160a01b0384169081179091556040805163288688f960e21b8152905191925063a21a23e49160048083019260209291908290030181600087803b1580156200013b57600080fd5b505af115801562000150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001769190620002f1565b600280546001600160401b03928316600160a01b908102600160a01b600160e01b03198316811793849055604051631cd0704360e21b81529190930490931660048401523060248401526001600160a01b0391821691161790637341c10c90604401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b50505050506200031c565b6001600160a01b0381163314156200026e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620002d257600080fd5b81516001600160a01b0381168114620002ea57600080fd5b9392505050565b6000602082840312156200030457600080fd5b81516001600160401b0381168114620002ea57600080fd5b60805160601c61106c62000342600039600081816103000152610368015261106c6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063a168fa8911610097578063d8a4676f11610066578063d8a4676f14610262578063dc1670db14610287578063eb1d28bb14610290578063f2fde38b146102d557600080fd5b8063a168fa89146101bc578063ad603ea214610227578063b1e217491461023a578063d826f88f1461024357600080fd5b8063737144bc116100d3578063737144bc1461018457806374dba1241461018d57806379ba5097146101965780638da5cb5b1461019e57600080fd5b80631757f11c146101055780631fe543e3146101215780633b2bcbf114610136578063557d2e921461017b575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610da4565b6102e8565b005b6002546101569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b61010e60045481565b61010e60055481565b61010e60075481565b6101346103a8565b60005473ffffffffffffffffffffffffffffffffffffffff16610156565b6101fd6101ca366004610d72565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b610134610235366004610d14565b6104a5565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b610275610270366004610d72565b610809565b60405161011896959493929190610e93565b61010e60035481565b6002546102bc9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610118565b6101346102e3366004610cd7565b6108ee565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461039a576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6103a48282610902565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610429576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610391565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104ad610a2d565b60005b8161ffff168161ffff1610156106ad576002546040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810187905274010000000000000000000000000000000000000000820467ffffffffffffffff16602482015261ffff8816604482015263ffffffff80871660648301528516608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561057257600080fd5b505af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa9190610d8b565b6008819055905060006105bb610ab0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610649926001850192910190610c4c565b506040820151600282015560608201516003820155608082015160048083019190915560a090920151600590910155805490600061068683610fc8565b909155505060009182526009602052604090912055806106a581610fa6565b9150506104b0565b506002546040517f9f87fad700000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b50506002546040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b1580156107ea57600080fd5b505af11580156107fe573d6000803e3d6000fd5b505050505050505050565b6000818152600a60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561088757602002820191906000526020600020905b815481526020019060010190808311610873575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6108f6610a2d565b6108ff81610b56565b50565b600061090c610ab0565b600084815260096020526040812054919250906109299083610f8f565b9050600061093a82620f4240610f52565b905060065482111561094c5760068290555b600754821061095d5760075461095f565b815b60075560035461096f57806109a2565b60035461097d906001610eff565b8160035460055461098e9190610f52565b6109989190610eff565b6109a29190610f17565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117825586516109f4939290910191870190610c4c565b506000858152600a60205260408120426003808301919091556005909101859055805491610a2183610fc8565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610391565b565b60004661a4b1811480610ac5575062066eed81145b15610b4f57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b1157600080fd5b505afa158015610b25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b499190610d8b565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610391565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610c87579160200282015b82811115610c87578251825591602001919060010190610c6c565b50610c93929150610c97565b5090565b5b80821115610c935760008155600101610c98565b803561ffff81168114610cbe57600080fd5b919050565b803563ffffffff81168114610cbe57600080fd5b600060208284031215610ce957600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d0d57600080fd5b9392505050565b600080600080600060a08688031215610d2c57600080fd5b610d3586610cac565b945060208601359350610d4a60408701610cc3565b9250610d5860608701610cc3565b9150610d6660808701610cac565b90509295509295909350565b600060208284031215610d8457600080fd5b5035919050565b600060208284031215610d9d57600080fd5b5051919050565b60008060408385031215610db757600080fd5b8235915060208084013567ffffffffffffffff80821115610dd757600080fd5b818601915086601f830112610deb57600080fd5b813581811115610dfd57610dfd611030565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e4057610e40611030565b604052828152858101935084860182860187018b1015610e5f57600080fd5b600095505b83861015610e82578035855260019590950194938601938601610e64565b508096505050505050509250929050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610ed657845183529383019391830191600101610eba565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610f1257610f12611001565b500190565b600082610f4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610f8a57610f8a611001565b500290565b600082821015610fa157610fa1611001565b500390565b600061ffff80831681811415610fbe57610fbe611001565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610ffa57610ffa611001565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b50604051620013cc380380620013cc8339810160408190526200004491620002bf565b6001600160601b0319606082901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000213565b5050600280546001600160a01b0319166001600160a01b0384169081179091556040805163288688f960e21b8152905191925063a21a23e49160048083019260209291908290030181600087803b1580156200013b57600080fd5b505af115801562000150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001769190620002f1565b600280546001600160401b03928316600160a01b908102600160a01b600160e01b03198316811793849055604051631cd0704360e21b81529190930490931660048401523060248401526001600160a01b0391821691161790637341c10c90604401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b50505050506200031c565b6001600160a01b0381163314156200026e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620002d257600080fd5b81516001600160a01b0381168114620002ea57600080fd5b9392505050565b6000602082840312156200030457600080fd5b81516001600160401b0381168114620002ea57600080fd5b60805160601c61108a62000342600039600081816103000152610368015261108a6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063a168fa8911610097578063d8a4676f11610066578063d8a4676f14610262578063dc1670db14610287578063eb1d28bb14610290578063f2fde38b146102d557600080fd5b8063a168fa89146101bc578063ad603ea214610227578063b1e217491461023a578063d826f88f1461024357600080fd5b8063737144bc116100d3578063737144bc1461018457806374dba1241461018d57806379ba5097146101965780638da5cb5b1461019e57600080fd5b80631757f11c146101055780631fe543e3146101215780633b2bcbf114610136578063557d2e921461017b575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610dc2565b6102e8565b005b6002546101569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b61010e60045481565b61010e60055481565b61010e60075481565b6101346103a8565b60005473ffffffffffffffffffffffffffffffffffffffff16610156565b6101fd6101ca366004610d90565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b610134610235366004610d32565b6104a5565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b610275610270366004610d90565b610809565b60405161011896959493929190610eb1565b61010e60035481565b6002546102bc9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610118565b6101346102e3366004610cf5565b6108ee565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461039a576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6103a48282610902565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610429576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610391565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104ad610a2d565b60005b8161ffff168161ffff1610156106ad576002546040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810187905274010000000000000000000000000000000000000000820467ffffffffffffffff16602482015261ffff8816604482015263ffffffff80871660648301528516608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561057257600080fd5b505af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa9190610da9565b6008819055905060006105bb610ab0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610649926001850192910190610c6a565b506040820151600282015560608201516003820155608082015160048083019190915560a090920151600590910155805490600061068683610fe6565b909155505060009182526009602052604090912055806106a581610fc4565b9150506104b0565b506002546040517f9f87fad700000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b50506002546040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b1580156107ea57600080fd5b505af11580156107fe573d6000803e3d6000fd5b505050505050505050565b6000818152600a60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561088757602002820191906000526020600020905b815481526020019060010190808311610873575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6108f6610a2d565b6108ff81610b4d565b50565b600061090c610ab0565b600084815260096020526040812054919250906109299083610fad565b9050600061093a82620f4240610f70565b905060065482111561094c5760068290555b600754821061095d5760075461095f565b815b60075560035461096f57806109a2565b60035461097d906001610f1d565b8160035460055461098e9190610f70565b6109989190610f1d565b6109a29190610f35565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117825586516109f4939290910191870190610c6a565b506000858152600a60205260408120426003808301919091556005909101859055805491610a2183610fe6565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610391565b565b600046610abc81610c43565b15610b4657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0857600080fd5b505afa158015610b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b409190610da9565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bcd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610391565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610c57575062066eed82145b80610c64575062066eee82145b92915050565b828054828255906000526020600020908101928215610ca5579160200282015b82811115610ca5578251825591602001919060010190610c8a565b50610cb1929150610cb5565b5090565b5b80821115610cb15760008155600101610cb6565b803561ffff81168114610cdc57600080fd5b919050565b803563ffffffff81168114610cdc57600080fd5b600060208284031215610d0757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d2b57600080fd5b9392505050565b600080600080600060a08688031215610d4a57600080fd5b610d5386610cca565b945060208601359350610d6860408701610ce1565b9250610d7660608701610ce1565b9150610d8460808701610cca565b90509295509295909350565b600060208284031215610da257600080fd5b5035919050565b600060208284031215610dbb57600080fd5b5051919050565b60008060408385031215610dd557600080fd5b8235915060208084013567ffffffffffffffff80821115610df557600080fd5b818601915086601f830112610e0957600080fd5b813581811115610e1b57610e1b61104e565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e5e57610e5e61104e565b604052828152858101935084860182860187018b1015610e7d57600080fd5b600095505b83861015610ea0578035855260019590950194938601938601610e82565b508096505050505050509250929050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610ef457845183529383019391830191600101610ed8565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610f3057610f3061101f565b500190565b600082610f6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610fa857610fa861101f565b500290565b600082821015610fbf57610fbf61101f565b500390565b600061ffff80831681811415610fdc57610fdc61101f565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156110185761101861101f565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2OwnerTestConsumerABI = VRFV2OwnerTestConsumerMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go b/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go new file mode 100644 index 00000000000..a5d57945802 --- /dev/null +++ b/core/gethwrappers/generated/vrf_v2_consumer_wrapper/vrf_v2_consumer_wrapper.go @@ -0,0 +1,951 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_v2_consumer_wrapper + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var VRFv2ConsumerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"requestIds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exists\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a060405234801561001057600080fd5b50604051610e31380380610e3183398101604081905261002f9161019a565b6001600160601b0319606082901b1660805233806000816100975760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100c7576100c7816100f0565b5050600380546001600160a01b0319166001600160a01b039390931692909217909155506101ca565b6001600160a01b0381163314156101495760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161008e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ac57600080fd5b81516001600160a01b03811681146101c357600080fd5b9392505050565b60805160601c610c426101ef600039600081816101be01526102260152610c426000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639561f02311610076578063d8a4676f1161005b578063d8a4676f14610169578063f2fde38b1461018a578063fc2a88c31461019d57600080fd5b80639561f02314610113578063a168fa891461012657600080fd5b80631fe543e3146100a857806379ba5097146100bd5780638796ba8c146100c55780638da5cb5b146100eb575b600080fd5b6100bb6100b6366004610a2c565b6101a6565b005b6100bb610266565b6100d86100d33660046109fa565b610363565b6040519081526020015b60405180910390f35b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e2565b6100d8610121366004610b1b565b610384565b6101526101343660046109fa565b60026020526000908152604090205460ff8082169161010090041682565b6040805192151583529015156020830152016100e2565b61017c6101773660046109fa565b610593565b6040516100e2929190610bca565b6100bb6101983660046109bd565b6106ad565b6100d860055481565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610258576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61026282826106c1565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161024f565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6004818154811061037357600080fd5b600091825260209091200154905081565b600061038e6107cb565b6003546040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810184905267ffffffffffffffff8816602482015261ffff8616604482015263ffffffff80881660648301528516608482015273ffffffffffffffffffffffffffffffffffffffff90911690635d3b1d309060a401602060405180830381600087803b15801561042857600080fd5b505af115801561043c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104609190610a13565b604080516060810182526000808252600160208084018281528551848152808301875285870190815287855260028352959093208451815494517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169015157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff161761010094151594909402939093178355935180519596509294919361050f9391850192910190610944565b5050600480546001810182556000919091527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b018290555060058190556040805182815263ffffffff851660208201527fcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee910160405180910390a195945050505050565b600081815260026020526040812054606090610100900460ff16610613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161024f565b60008381526002602090815260408083208151606081018352815460ff808216151583526101009091041615158185015260018201805484518187028101870186528181529295939486019383018282801561068e57602002820191906000526020600020905b81548152602001906001019080831161067a575b5050505050815250509050806000015181604001519250925050915091565b6106b56107cb565b6106be8161084e565b50565b600082815260026020526040902054610100900460ff1661073e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161024f565b600082815260026020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255835161078d939290910191840190610944565b507ffe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d82826040516107bf929190610bed565b60405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461084c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161024f565b565b73ffffffffffffffffffffffffffffffffffffffff81163314156108ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161024f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b82805482825590600052602060002090810192821561097f579160200282015b8281111561097f578251825591602001919060010190610964565b5061098b92915061098f565b5090565b5b8082111561098b5760008155600101610990565b803563ffffffff811681146109b857600080fd5b919050565b6000602082840312156109cf57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146109f357600080fd5b9392505050565b600060208284031215610a0c57600080fd5b5035919050565b600060208284031215610a2557600080fd5b5051919050565b60008060408385031215610a3f57600080fd5b8235915060208084013567ffffffffffffffff80821115610a5f57600080fd5b818601915086601f830112610a7357600080fd5b813581811115610a8557610a85610c06565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610ac857610ac8610c06565b604052828152858101935084860182860187018b1015610ae757600080fd5b600095505b83861015610b0a578035855260019590950194938601938601610aec565b508096505050505050509250929050565b600080600080600060a08688031215610b3357600080fd5b853567ffffffffffffffff81168114610b4b57600080fd5b9450610b59602087016109a4565b9350604086013561ffff81168114610b7057600080fd5b9250610b7e606087016109a4565b949793965091946080013592915050565b600081518084526020808501945080840160005b83811015610bbf57815187529582019590820190600101610ba3565b509495945050505050565b8215158152604060208201526000610be56040830184610b8f565b949350505050565b828152604060208201526000610be56040830184610b8f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var VRFv2ConsumerABI = VRFv2ConsumerMetaData.ABI + +var VRFv2ConsumerBin = VRFv2ConsumerMetaData.Bin + +func DeployVRFv2Consumer(auth *bind.TransactOpts, backend bind.ContractBackend, vrfCoordinator common.Address) (common.Address, *types.Transaction, *VRFv2Consumer, error) { + parsed, err := VRFv2ConsumerMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFv2ConsumerBin), backend, vrfCoordinator) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFv2Consumer{VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil +} + +type VRFv2Consumer struct { + address common.Address + abi abi.ABI + VRFv2ConsumerCaller + VRFv2ConsumerTransactor + VRFv2ConsumerFilterer +} + +type VRFv2ConsumerCaller struct { + contract *bind.BoundContract +} + +type VRFv2ConsumerTransactor struct { + contract *bind.BoundContract +} + +type VRFv2ConsumerFilterer struct { + contract *bind.BoundContract +} + +type VRFv2ConsumerSession struct { + Contract *VRFv2Consumer + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFv2ConsumerCallerSession struct { + Contract *VRFv2ConsumerCaller + CallOpts bind.CallOpts +} + +type VRFv2ConsumerTransactorSession struct { + Contract *VRFv2ConsumerTransactor + TransactOpts bind.TransactOpts +} + +type VRFv2ConsumerRaw struct { + Contract *VRFv2Consumer +} + +type VRFv2ConsumerCallerRaw struct { + Contract *VRFv2ConsumerCaller +} + +type VRFv2ConsumerTransactorRaw struct { + Contract *VRFv2ConsumerTransactor +} + +func NewVRFv2Consumer(address common.Address, backend bind.ContractBackend) (*VRFv2Consumer, error) { + abi, err := abi.JSON(strings.NewReader(VRFv2ConsumerABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFv2Consumer(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFv2Consumer{address: address, abi: abi, VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil +} + +func NewVRFv2ConsumerCaller(address common.Address, caller bind.ContractCaller) (*VRFv2ConsumerCaller, error) { + contract, err := bindVRFv2Consumer(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFv2ConsumerCaller{contract: contract}, nil +} + +func NewVRFv2ConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFv2ConsumerTransactor, error) { + contract, err := bindVRFv2Consumer(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFv2ConsumerTransactor{contract: contract}, nil +} + +func NewVRFv2ConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFv2ConsumerFilterer, error) { + contract, err := bindVRFv2Consumer(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFv2ConsumerFilterer{contract: contract}, nil +} + +func bindVRFv2Consumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFv2ConsumerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFv2Consumer *VRFv2ConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFv2Consumer.Contract.VRFv2ConsumerCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFv2Consumer *VRFv2ConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.VRFv2ConsumerTransactor.contract.Transfer(opts) +} + +func (_VRFv2Consumer *VRFv2ConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.VRFv2ConsumerTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFv2Consumer.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.contract.Transfer(opts) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFv2Consumer *VRFv2ConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) { + var out []interface{} + err := _VRFv2Consumer.contract.Call(opts, &out, "getRequestStatus", _requestId) + + outstruct := new(GetRequestStatus) + if err != nil { + return *outstruct, err + } + + outstruct.Fulfilled = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.RandomWords = *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int) + + return *outstruct, err + +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFv2Consumer.Contract.GetRequestStatus(&_VRFv2Consumer.CallOpts, _requestId) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFv2Consumer.Contract.GetRequestStatus(&_VRFv2Consumer.CallOpts, _requestId) +} + +func (_VRFv2Consumer *VRFv2ConsumerCaller) LastRequestId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFv2Consumer.contract.Call(opts, &out, "lastRequestId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) LastRequestId() (*big.Int, error) { + return _VRFv2Consumer.Contract.LastRequestId(&_VRFv2Consumer.CallOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerSession) LastRequestId() (*big.Int, error) { + return _VRFv2Consumer.Contract.LastRequestId(&_VRFv2Consumer.CallOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFv2Consumer.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) Owner() (common.Address, error) { + return _VRFv2Consumer.Contract.Owner(&_VRFv2Consumer.CallOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerSession) Owner() (common.Address, error) { + return _VRFv2Consumer.Contract.Owner(&_VRFv2Consumer.CallOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerCaller) RequestIds(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { + var out []interface{} + err := _VRFv2Consumer.contract.Call(opts, &out, "requestIds", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) RequestIds(arg0 *big.Int) (*big.Int, error) { + return _VRFv2Consumer.Contract.RequestIds(&_VRFv2Consumer.CallOpts, arg0) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerSession) RequestIds(arg0 *big.Int) (*big.Int, error) { + return _VRFv2Consumer.Contract.RequestIds(&_VRFv2Consumer.CallOpts, arg0) +} + +func (_VRFv2Consumer *VRFv2ConsumerCaller) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) { + var out []interface{} + err := _VRFv2Consumer.contract.Call(opts, &out, "s_requests", arg0) + + outstruct := new(SRequests) + if err != nil { + return *outstruct, err + } + + outstruct.Fulfilled = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Exists = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFv2Consumer.Contract.SRequests(&_VRFv2Consumer.CallOpts, arg0) +} + +func (_VRFv2Consumer *VRFv2ConsumerCallerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFv2Consumer.Contract.SRequests(&_VRFv2Consumer.CallOpts, arg0) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFv2Consumer.contract.Transact(opts, "acceptOwnership") +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFv2Consumer.Contract.AcceptOwnership(&_VRFv2Consumer.TransactOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFv2Consumer.Contract.AcceptOwnership(&_VRFv2Consumer.TransactOpts) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { + return _VRFv2Consumer.contract.Transact(opts, "rawFulfillRandomWords", requestId, randomWords) +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) RawFulfillRandomWords(requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.RawFulfillRandomWords(&_VRFv2Consumer.TransactOpts, requestId, randomWords) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) RawFulfillRandomWords(requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.RawFulfillRandomWords(&_VRFv2Consumer.TransactOpts, requestId, randomWords) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { + return _VRFv2Consumer.contract.Transact(opts, "requestRandomWords", subId, callbackGasLimit, requestConfirmations, numWords, keyHash) +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) RequestRandomWords(subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.RequestRandomWords(&_VRFv2Consumer.TransactOpts, subId, callbackGasLimit, requestConfirmations, numWords, keyHash) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) RequestRandomWords(subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.RequestRandomWords(&_VRFv2Consumer.TransactOpts, subId, callbackGasLimit, requestConfirmations, numWords, keyHash) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFv2Consumer.contract.Transact(opts, "transferOwnership", to) +} + +func (_VRFv2Consumer *VRFv2ConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.TransferOwnership(&_VRFv2Consumer.TransactOpts, to) +} + +func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFv2Consumer.Contract.TransferOwnership(&_VRFv2Consumer.TransactOpts, to) +} + +type VRFv2ConsumerOwnershipTransferRequestedIterator struct { + Event *VRFv2ConsumerOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerOwnershipTransferRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFv2ConsumerOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferRequestedIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFv2ConsumerOwnershipTransferRequestedIterator{contract: _VRFv2Consumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFv2ConsumerOwnershipTransferRequested) + if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFv2ConsumerOwnershipTransferRequested, error) { + event := new(VRFv2ConsumerOwnershipTransferRequested) + if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFv2ConsumerOwnershipTransferredIterator struct { + Event *VRFv2ConsumerOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFv2ConsumerOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFv2ConsumerOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFv2ConsumerOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFv2ConsumerOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferredIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFv2ConsumerOwnershipTransferredIterator{contract: _VRFv2Consumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFv2ConsumerOwnershipTransferred) + if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*VRFv2ConsumerOwnershipTransferred, error) { + event := new(VRFv2ConsumerOwnershipTransferred) + if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFv2ConsumerRequestFulfilledIterator struct { + Event *VRFv2ConsumerRequestFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFv2ConsumerRequestFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerRequestFulfilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerRequestFulfilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFv2ConsumerRequestFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFv2ConsumerRequestFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFv2ConsumerRequestFulfilled struct { + RequestId *big.Int + RandomWords []*big.Int + Raw types.Log +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterRequestFulfilled(opts *bind.FilterOpts) (*VRFv2ConsumerRequestFulfilledIterator, error) { + + logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "RequestFulfilled") + if err != nil { + return nil, err + } + return &VRFv2ConsumerRequestFulfilledIterator{contract: _VRFv2Consumer.contract, event: "RequestFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestFulfilled) (event.Subscription, error) { + + logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "RequestFulfilled") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFv2ConsumerRequestFulfilled) + if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestFulfilled", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseRequestFulfilled(log types.Log) (*VRFv2ConsumerRequestFulfilled, error) { + event := new(VRFv2ConsumerRequestFulfilled) + if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFv2ConsumerRequestSentIterator struct { + Event *VRFv2ConsumerRequestSent + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFv2ConsumerRequestSentIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerRequestSent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(VRFv2ConsumerRequestSent) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *VRFv2ConsumerRequestSentIterator) Error() error { + return it.fail +} + +func (it *VRFv2ConsumerRequestSentIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFv2ConsumerRequestSent struct { + RequestId *big.Int + NumWords uint32 + Raw types.Log +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterRequestSent(opts *bind.FilterOpts) (*VRFv2ConsumerRequestSentIterator, error) { + + logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "RequestSent") + if err != nil { + return nil, err + } + return &VRFv2ConsumerRequestSentIterator{contract: _VRFv2Consumer.contract, event: "RequestSent", logs: logs, sub: sub}, nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchRequestSent(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestSent) (event.Subscription, error) { + + logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "RequestSent") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFv2ConsumerRequestSent) + if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestSent", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseRequestSent(log types.Log) (*VRFv2ConsumerRequestSent, error) { + event := new(VRFv2ConsumerRequestSent) + if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestSent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetRequestStatus struct { + Fulfilled bool + RandomWords []*big.Int +} +type SRequests struct { + Fulfilled bool + Exists bool +} + +func (_VRFv2Consumer *VRFv2Consumer) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFv2Consumer.abi.Events["OwnershipTransferRequested"].ID: + return _VRFv2Consumer.ParseOwnershipTransferRequested(log) + case _VRFv2Consumer.abi.Events["OwnershipTransferred"].ID: + return _VRFv2Consumer.ParseOwnershipTransferred(log) + case _VRFv2Consumer.abi.Events["RequestFulfilled"].ID: + return _VRFv2Consumer.ParseRequestFulfilled(log) + case _VRFv2Consumer.abi.Events["RequestSent"].ID: + return _VRFv2Consumer.ParseRequestSent(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFv2ConsumerOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (VRFv2ConsumerOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (VRFv2ConsumerRequestFulfilled) Topic() common.Hash { + return common.HexToHash("0xfe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d") +} + +func (VRFv2ConsumerRequestSent) Topic() common.Hash { + return common.HexToHash("0xcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee") +} + +func (_VRFv2Consumer *VRFv2Consumer) Address() common.Address { + return _VRFv2Consumer.address +} + +type VRFv2ConsumerInterface interface { + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) + + LastRequestId(opts *bind.CallOpts) (*big.Int, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + RequestIds(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) + + SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) + + RequestRandomWords(opts *bind.TransactOpts, subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*VRFv2ConsumerOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*VRFv2ConsumerOwnershipTransferred, error) + + FilterRequestFulfilled(opts *bind.FilterOpts) (*VRFv2ConsumerRequestFulfilledIterator, error) + + WatchRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestFulfilled) (event.Subscription, error) + + ParseRequestFulfilled(log types.Log) (*VRFv2ConsumerRequestFulfilled, error) + + FilterRequestSent(opts *bind.FilterOpts) (*VRFv2ConsumerRequestSentIterator, error) + + WatchRequestSent(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestSent) (event.Subscription, error) + + ParseRequestSent(log types.Log) (*VRFv2ConsumerRequestSent, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go index 9bb00660e12..c8971595c53 100644 --- a/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics/vrf_v2plus_load_test_with_metrics.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusLoadTestWithMetricsMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"_nativePayment\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6080604052600060055560006006556103e760075534801561002057600080fd5b5060405161134738038061134783398101604081905261003f9161019b565b8033806000816100965760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100c6576100c6816100f1565b5050600280546001600160a01b0319166001600160a01b039390931692909217909155506101cb9050565b6001600160a01b03811633141561014a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161008d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ad57600080fd5b81516001600160a01b03811681146101c457600080fd5b9392505050565b61116d806101da6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638ea9811711610097578063d826f88f11610066578063d826f88f14610252578063d8a4676f14610271578063dc1670db14610296578063f2fde38b1461029f57600080fd5b80638ea98117146101ab5780639eccacf6146101be578063a168fa89146101de578063b1e217491461024957600080fd5b8063737144bc116100d3578063737144bc1461015257806374dba1241461015b57806379ba5097146101645780638da5cb5b1461016c57600080fd5b80631757f11c146101055780631fe543e314610121578063557d2e92146101365780636846de201461013f575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610d66565b6102b2565b005b61010e60045481565b61013461014d366004610e55565b610338565b61010e60055481565b61010e60075481565b610134610565565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b6101346101b9366004610cf7565b610662565b6002546101869073ffffffffffffffffffffffffffffffffffffffff1681565b61021f6101ec366004610d34565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b61028461027f366004610d34565b61076d565b60405161011896959493929190610ed4565b61010e60035481565b6101346102ad366004610cf7565b610852565b60025473ffffffffffffffffffffffffffffffffffffffff16331461032a576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103348282610866565b5050565b610340610991565b60005b8161ffff168161ffff16101561055b5760006040518060c001604052808881526020018a81526020018961ffff1681526020018763ffffffff1681526020018563ffffffff1681526020016103a76040518060200160405280891515815250610a14565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90610405908590600401610f40565b602060405180830381600087803b15801561041f57600080fd5b505af1158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190610d4d565b600881905590506000610468610ad0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517815590518051949550919390926104f6926001850192910190610c6c565b506040820151600282015560608201516003820155608082015160048083019190915560a0909201516005909101558054906000610533836110c9565b9091555050600091825260096020526040909120555080610553816110a7565b915050610343565b5050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610321565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906106a2575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561072657336106c760005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610321565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000818152600a60209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156107eb57602002820191906000526020600020905b8154815260200190600101908083116107d7575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b61085a610991565b61086381610b76565b50565b6000610870610ad0565b6000848152600960205260408120549192509061088d9083611090565b9050600061089e82620f4240611053565b90506006548211156108b05760068290555b60075482106108c1576007546108c3565b815b6007556003546108d35780610906565b6003546108e1906001611000565b816003546005546108f29190611053565b6108fc9190611000565b6109069190611018565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558651610958939290910191870190610c6c565b506000858152600a60205260408120426003808301919091556005909101859055805491610985836110c9565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610321565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610a4d91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b60004661a4b1811480610ae5575062066eed81145b15610b6f57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3157600080fd5b505afa158015610b45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b699190610d4d565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610321565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610ca7579160200282015b82811115610ca7578251825591602001919060010190610c8c565b50610cb3929150610cb7565b5090565b5b80821115610cb35760008155600101610cb8565b803561ffff81168114610cde57600080fd5b919050565b803563ffffffff81168114610cde57600080fd5b600060208284031215610d0957600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d2d57600080fd5b9392505050565b600060208284031215610d4657600080fd5b5035919050565b600060208284031215610d5f57600080fd5b5051919050565b60008060408385031215610d7957600080fd5b8235915060208084013567ffffffffffffffff80821115610d9957600080fd5b818601915086601f830112610dad57600080fd5b813581811115610dbf57610dbf611131565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e0257610e02611131565b604052828152858101935084860182860187018b1015610e2157600080fd5b600095505b83861015610e44578035855260019590950194938601938601610e26565b508096505050505050509250929050565b600080600080600080600060e0888a031215610e7057600080fd5b87359650610e8060208901610ccc565b955060408801359450610e9560608901610ce3565b935060808801358015158114610eaa57600080fd5b9250610eb860a08901610ce3565b9150610ec660c08901610ccc565b905092959891949750929550565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610f1757845183529383019391830191600101610efb565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610fb75782810184015186820161010001528301610f9a565b81811115610fca57600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b6000821982111561101357611013611102565b500190565b60008261104e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561108b5761108b611102565b500290565b6000828210156110a2576110a2611102565b500390565b600061ffff808316818114156110bf576110bf611102565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156110fb576110fb611102565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x6080604052600060055560006006556103e760075534801561002057600080fd5b5060405161136538038061136583398101604081905261003f9161019b565b8033806000816100965760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100c6576100c6816100f1565b5050600280546001600160a01b0319166001600160a01b039390931692909217909155506101cb9050565b6001600160a01b03811633141561014a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161008d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ad57600080fd5b81516001600160a01b03811681146101c457600080fd5b9392505050565b61118b806101da6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638ea9811711610097578063d826f88f11610066578063d826f88f14610252578063d8a4676f14610271578063dc1670db14610296578063f2fde38b1461029f57600080fd5b80638ea98117146101ab5780639eccacf6146101be578063a168fa89146101de578063b1e217491461024957600080fd5b8063737144bc116100d3578063737144bc1461015257806374dba1241461015b57806379ba5097146101645780638da5cb5b1461016c57600080fd5b80631757f11c146101055780631fe543e314610121578063557d2e92146101365780636846de201461013f575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610d84565b6102b2565b005b61010e60045481565b61013461014d366004610e73565b610338565b61010e60055481565b61010e60075481565b610134610565565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b6101346101b9366004610d15565b610662565b6002546101869073ffffffffffffffffffffffffffffffffffffffff1681565b61021f6101ec366004610d52565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b61028461027f366004610d52565b61076d565b60405161011896959493929190610ef2565b61010e60035481565b6101346102ad366004610d15565b610852565b60025473ffffffffffffffffffffffffffffffffffffffff16331461032a576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103348282610866565b5050565b610340610991565b60005b8161ffff168161ffff16101561055b5760006040518060c001604052808881526020018a81526020018961ffff1681526020018763ffffffff1681526020018563ffffffff1681526020016103a76040518060200160405280891515815250610a14565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90610405908590600401610f5e565b602060405180830381600087803b15801561041f57600080fd5b505af1158015610433573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190610d6b565b600881905590506000610468610ad0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690151517815590518051949550919390926104f6926001850192910190610c8a565b506040820151600282015560608201516003820155608082015160048083019190915560a0909201516005909101558054906000610533836110e7565b9091555050600091825260096020526040909120555080610553816110c5565b915050610343565b5050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610321565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906106a2575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561072657336106c760005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610321565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000818152600a60209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156107eb57602002820191906000526020600020905b8154815260200190600101908083116107d7575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b61085a610991565b61086381610b6d565b50565b6000610870610ad0565b6000848152600960205260408120549192509061088d90836110ae565b9050600061089e82620f4240611071565b90506006548211156108b05760068290555b60075482106108c1576007546108c3565b815b6007556003546108d35780610906565b6003546108e190600161101e565b816003546005546108f29190611071565b6108fc919061101e565b6109069190611036565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558651610958939290910191870190610c8a565b506000858152600a60205260408120426003808301919091556005909101859055805491610985836110e7565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610321565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610a4d91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b600046610adc81610c63565b15610b6657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2857600080fd5b505afa158015610b3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b609190610d6b565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610321565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610c77575062066eed82145b80610c84575062066eee82145b92915050565b828054828255906000526020600020908101928215610cc5579160200282015b82811115610cc5578251825591602001919060010190610caa565b50610cd1929150610cd5565b5090565b5b80821115610cd15760008155600101610cd6565b803561ffff81168114610cfc57600080fd5b919050565b803563ffffffff81168114610cfc57600080fd5b600060208284031215610d2757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d4b57600080fd5b9392505050565b600060208284031215610d6457600080fd5b5035919050565b600060208284031215610d7d57600080fd5b5051919050565b60008060408385031215610d9757600080fd5b8235915060208084013567ffffffffffffffff80821115610db757600080fd5b818601915086601f830112610dcb57600080fd5b813581811115610ddd57610ddd61114f565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e2057610e2061114f565b604052828152858101935084860182860187018b1015610e3f57600080fd5b600095505b83861015610e62578035855260019590950194938601938601610e44565b508096505050505050509250929050565b600080600080600080600060e0888a031215610e8e57600080fd5b87359650610e9e60208901610cea565b955060408801359450610eb360608901610d01565b935060808801358015158114610ec857600080fd5b9250610ed660a08901610d01565b9150610ee460c08901610cea565b905092959891949750929550565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610f3557845183529383019391830191600101610f19565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610fd55782810184015186820161010001528301610fb8565b81811115610fe857600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b6000821982111561103157611031611120565b500190565b60008261106c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156110a9576110a9611120565b500290565b6000828210156110c0576110c0611120565b500390565b600061ffff808316818114156110dd576110dd611120565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561111957611119611120565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusLoadTestWithMetricsABI = VRFV2PlusLoadTestWithMetricsMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go index 6e0f5f3ccd8..afa659269db 100644 --- a/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go +++ b/core/gethwrappers/generated/vrf_v2plus_single_consumer/vrf_v2plus_single_consumer.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusSingleConsumerExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"fundAndRequestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestConfig\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"subscribe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"unsubscribe\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b506040516200186338038062001863833981016040819052620000349162000464565b8633806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001b4565b5050600280546001600160a01b03199081166001600160a01b03948516179091556003805482168b8516179055600480548216938a169390931790925550600b80543392169190911790556040805160c081018252600080825263ffffffff8881166020840181905261ffff8916948401859052908716606084018190526080840187905285151560a09094018490526005929092556006805465ffffffffffff19169091176401000000009094029390931763ffffffff60301b191666010000000000009091021790915560078390556008805460ff19169091179055620001a762000260565b5050505050505062000530565b6001600160a01b0381163314156200020f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200026a620003d4565b604080516001808252818301909252600091602080830190803683370190505090503081600081518110620002a357620002a36200051a565b6001600160a01b039283166020918202929092018101919091526003546040805163288688f960e21b81529051919093169263a21a23e49260048083019391928290030181600087803b158015620002fa57600080fd5b505af11580156200030f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000335919062000500565b600581905560035482516001600160a01b039091169163bec4c08c9184906000906200036557620003656200051a565b60200260200101516040518363ffffffff1660e01b81526004016200039d9291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b158015620003b857600080fd5b505af1158015620003cd573d6000803e3d6000fd5b5050505050565b6000546001600160a01b03163314620004305760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000083565b565b80516001600160a01b03811681146200044a57600080fd5b919050565b805163ffffffff811681146200044a57600080fd5b600080600080600080600060e0888a0312156200048057600080fd5b6200048b8862000432565b96506200049b6020890162000432565b9550620004ab604089016200044f565b9450606088015161ffff81168114620004c357600080fd5b9350620004d3608089016200044f565b925060a0880151915060c08801518015158114620004f057600080fd5b8091505092959891949750929550565b6000602082840312156200051357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b61132380620005406000396000f3fe608060405234801561001057600080fd5b50600436106100f45760003560e01c80638da5cb5b11610097578063e0c8628911610066578063e0c862891461025c578063e89e106a14610264578063f2fde38b1461027b578063f6eaffc81461028e57600080fd5b80638da5cb5b146101e25780638ea98117146102215780638f449a05146102345780639eccacf61461023c57600080fd5b80637262561c116100d35780637262561c1461013457806379ba5097146101475780637db9263f1461014f57806386850e93146101cf57600080fd5b8062f714ce146100f95780631fe543e31461010e5780636fd700bb14610121575b600080fd5b61010c61010736600461108f565b6102a1565b005b61010c61011c3660046110bb565b61035c565b61010c61012f36600461105d565b6103e2565b61010c610142366004611019565b610618565b61010c6106b8565b60055460065460075460085461018b939263ffffffff8082169361ffff6401000000008404169366010000000000009093049091169160ff1686565b6040805196875263ffffffff958616602088015261ffff90941693860193909352921660608401526080830191909152151560a082015260c0015b60405180910390f35b61010c6101dd36600461105d565b6107b5565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b61010c61022f366004611019565b61088b565b61010c610996565b6002546101fc9073ffffffffffffffffffffffffffffffffffffffff1681565b61010c610b3b565b61026d600a5481565b6040519081526020016101c6565b61010c610289366004611019565b610ca8565b61026d61029c36600461105d565b610cbc565b6102a9610cdd565b600480546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116938201939093526024810185905291169063a9059cbb90604401602060405180830381600087803b15801561031f57600080fd5b505af1158015610333573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610357919061103b565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103d4576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103de8282610d60565b5050565b6103ea610cdd565b6040805160c08101825260055480825260065463ffffffff808216602080860191909152640100000000830461ffff16858701526601000000000000909204166060840152600754608084015260085460ff16151560a0840152600454600354855192830193909352929373ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016104a693929190611215565b602060405180830381600087803b1580156104c057600080fd5b505af11580156104d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f8919061103b565b5060006040518060c001604052808360800151815260200183600001518152602001836040015161ffff168152602001836020015163ffffffff168152602001836060015163ffffffff16815260200161056560405180602001604052808660a001511515815250610dde565b90526003546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906105be908490600401611253565b602060405180830381600087803b1580156105d857600080fd5b505af11580156105ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106109190611076565b600a55505050565b610620610cdd565b6003546005546040517f0ae09540000000000000000000000000000000000000000000000000000000008152600481019190915273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690630ae0954090604401600060405180830381600087803b15801561069857600080fd5b505af11580156106ac573d6000803e3d6000fd5b50506000600555505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103cb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6107bd610cdd565b6004546003546005546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361083993911691869190604401611215565b602060405180830381600087803b15801561085357600080fd5b505af1158015610867573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103de919061103b565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906108cb575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561094f57336108f060005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016103cb565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61099e610cdd565b6040805160018082528183019092526000916020808301908036833701905050905030816000815181106109d4576109d46112b8565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600354604080517fa21a23e40000000000000000000000000000000000000000000000000000000081529051919093169263a21a23e49260048083019391928290030181600087803b158015610a5057600080fd5b505af1158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a889190611076565b6005819055600354825173ffffffffffffffffffffffffffffffffffffffff9091169163bec4c08c918490600090610ac257610ac26112b8565b60200260200101516040518363ffffffff1660e01b8152600401610b0692919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610b2057600080fd5b505af1158015610b34573d6000803e3d6000fd5b5050505050565b610b43610cdd565b6040805160c08082018352600554825260065463ffffffff808216602080860191825261ffff640100000000850481168789019081526601000000000000909504841660608089019182526007546080808b0191825260085460ff16151560a0808d019182528d519b8c018e5292518b528b518b8801529851909416898c0152945186169088015251909316928501929092528551918201909552905115158152919260009290820190610bf690610dde565b90526003546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610c4f908490600401611253565b602060405180830381600087803b158015610c6957600080fd5b505af1158015610c7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca19190611076565b600a555050565b610cb0610cdd565b610cb981610e9a565b50565b60098181548110610ccc57600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103cb565b565b600a548214610dcb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016103cb565b8051610357906009906020840190610f90565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610e1791511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff8116331415610f1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103cb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610fcb579160200282015b82811115610fcb578251825591602001919060010190610fb0565b50610fd7929150610fdb565b5090565b5b80821115610fd75760008155600101610fdc565b803573ffffffffffffffffffffffffffffffffffffffff8116811461101457600080fd5b919050565b60006020828403121561102b57600080fd5b61103482610ff0565b9392505050565b60006020828403121561104d57600080fd5b8151801515811461103457600080fd5b60006020828403121561106f57600080fd5b5035919050565b60006020828403121561108857600080fd5b5051919050565b600080604083850312156110a257600080fd5b823591506110b260208401610ff0565b90509250929050565b600080604083850312156110ce57600080fd5b8235915060208084013567ffffffffffffffff808211156110ee57600080fd5b818601915086601f83011261110257600080fd5b813581811115611114576111146112e7565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715611157576111576112e7565b604052828152858101935084860182860187018b101561117657600080fd5b600095505b8386101561119957803585526001959095019493860193860161117b565b508096505050505050509250929050565b6000815180845260005b818110156111d0576020818501810151868301820152016111b4565b818111156111e2576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061124a60608301846111aa565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c0808401526112b060e08401826111aa565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b506040516200185238038062001852833981016040819052620000349162000458565b8633806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001a8565b5050600280546001600160a01b03199081166001600160a01b0394851617909155600380548216938a169390931790925550600a80543392169190911790556040805160c081018252600080825263ffffffff8881166020840181905261ffff8916948401859052908716606084018190526080840187905285151560a09094018490526004929092556005805465ffffffffffff19169091176401000000009094029390931763ffffffff60301b191666010000000000009091021790915560068390556007805460ff191690911790556200019b62000254565b5050505050505062000524565b6001600160a01b038116331415620002035760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200025e620003c8565b6040805160018082528183019092526000916020808301908036833701905050905030816000815181106200029757620002976200050e565b6001600160a01b039283166020918202929092018101919091526002546040805163288688f960e21b81529051919093169263a21a23e49260048083019391928290030181600087803b158015620002ee57600080fd5b505af115801562000303573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003299190620004f4565b600481905560025482516001600160a01b039091169163bec4c08c9184906000906200035957620003596200050e565b60200260200101516040518363ffffffff1660e01b8152600401620003919291909182526001600160a01b0316602082015260400190565b600060405180830381600087803b158015620003ac57600080fd5b505af1158015620003c1573d6000803e3d6000fd5b5050505050565b6000546001600160a01b03163314620004245760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000083565b565b80516001600160a01b03811681146200043e57600080fd5b919050565b805163ffffffff811681146200043e57600080fd5b600080600080600080600060e0888a0312156200047457600080fd5b6200047f8862000426565b96506200048f6020890162000426565b95506200049f6040890162000443565b9450606088015161ffff81168114620004b757600080fd5b9350620004c76080890162000443565b925060a0880151915060c08801518015158114620004e457600080fd5b8091505092959891949750929550565b6000602082840312156200050757600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b61131e80620005346000396000f3fe608060405234801561001057600080fd5b50600436106100f45760003560e01c80638da5cb5b11610097578063e0c8628911610066578063e0c862891461025c578063e89e106a14610264578063f2fde38b1461027b578063f6eaffc81461028e57600080fd5b80638da5cb5b146101e25780638ea98117146102215780638f449a05146102345780639eccacf61461023c57600080fd5b80637262561c116100d35780637262561c1461013457806379ba5097146101475780637db9263f1461014f57806386850e93146101cf57600080fd5b8062f714ce146100f95780631fe543e31461010e5780636fd700bb14610121575b600080fd5b61010c61010736600461108a565b6102a1565b005b61010c61011c3660046110b6565b61035a565b61010c61012f366004611058565b6103e0565b61010c610142366004611014565b610616565b61010c6106b3565b60045460055460065460075461018b939263ffffffff8082169361ffff6401000000008404169366010000000000009093049091169160ff1686565b6040805196875263ffffffff958616602088015261ffff90941693860193909352921660608401526080830191909152151560a082015260c0015b60405180910390f35b61010c6101dd366004611058565b6107b0565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c6565b61010c61022f366004611014565b610886565b61010c610991565b6002546101fc9073ffffffffffffffffffffffffffffffffffffffff1681565b61010c610b36565b61026d60095481565b6040519081526020016101c6565b61010c610289366004611014565b610ca3565b61026d61029c366004611058565b610cb7565b6102a9610cd8565b6003546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018590529091169063a9059cbb90604401602060405180830381600087803b15801561031d57600080fd5b505af1158015610331573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103559190611036565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146103d2576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6103dc8282610d5b565b5050565b6103e8610cd8565b6040805160c08101825260045480825260055463ffffffff808216602080860191909152640100000000830461ffff16858701526601000000000000909204166060840152600654608084015260075460ff16151560a0840152600354600254855192830193909352929373ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918691016040516020818303038152906040526040518463ffffffff1660e01b81526004016104a493929190611210565b602060405180830381600087803b1580156104be57600080fd5b505af11580156104d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f69190611036565b5060006040518060c001604052808360800151815260200183600001518152602001836040015161ffff168152602001836020015163ffffffff168152602001836060015163ffffffff16815260200161056360405180602001604052808660a001511515815250610dd9565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906105bc90849060040161124e565b602060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060e9190611071565b600955505050565b61061e610cd8565b600254600480546040517f0ae095400000000000000000000000000000000000000000000000000000000081529182015273ffffffffffffffffffffffffffffffffffffffff838116602483015290911690630ae0954090604401600060405180830381600087803b15801561069357600080fd5b505af11580156106a7573d6000803e3d6000fd5b50506000600455505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103c9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6107b8610cd8565b6003546002546004546040805160208082019390935281518082039093018352808201918290527f4000aea00000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09361083493911691869190604401611210565b602060405180830381600087803b15801561084e57600080fd5b505af1158015610862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103dc9190611036565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906108c6575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561094a57336108eb60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016103c9565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610999610cd8565b6040805160018082528183019092526000916020808301908036833701905050905030816000815181106109cf576109cf6112b3565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600254604080517fa21a23e40000000000000000000000000000000000000000000000000000000081529051919093169263a21a23e49260048083019391928290030181600087803b158015610a4b57600080fd5b505af1158015610a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a839190611071565b6004819055600254825173ffffffffffffffffffffffffffffffffffffffff9091169163bec4c08c918490600090610abd57610abd6112b3565b60200260200101516040518363ffffffff1660e01b8152600401610b0192919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610b1b57600080fd5b505af1158015610b2f573d6000803e3d6000fd5b5050505050565b610b3e610cd8565b6040805160c08082018352600454825260055463ffffffff808216602080860191825261ffff640100000000850481168789019081526601000000000000909504841660608089019182526006546080808b0191825260075460ff16151560a0808d019182528d519b8c018e5292518b528b518b8801529851909416898c0152945186169088015251909316928501929092528551918201909552905115158152919260009290820190610bf190610dd9565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90610c4a90849060040161124e565b602060405180830381600087803b158015610c6457600080fd5b505af1158015610c78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9c9190611071565b6009555050565b610cab610cd8565b610cb481610e95565b50565b60088181548110610cc757600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d59576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103c9565b565b6009548214610dc6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016103c9565b8051610355906008906020840190610f8b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610e1291511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff8116331415610f15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103c9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610fc6579160200282015b82811115610fc6578251825591602001919060010190610fab565b50610fd2929150610fd6565b5090565b5b80821115610fd25760008155600101610fd7565b803573ffffffffffffffffffffffffffffffffffffffff8116811461100f57600080fd5b919050565b60006020828403121561102657600080fd5b61102f82610feb565b9392505050565b60006020828403121561104857600080fd5b8151801515811461102f57600080fd5b60006020828403121561106a57600080fd5b5035919050565b60006020828403121561108357600080fd5b5051919050565b6000806040838503121561109d57600080fd5b823591506110ad60208401610feb565b90509250929050565b600080604083850312156110c957600080fd5b8235915060208084013567ffffffffffffffff808211156110e957600080fd5b818601915086601f8301126110fd57600080fd5b81358181111561110f5761110f6112e2565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715611152576111526112e2565b604052828152858101935084860182860187018b101561117157600080fd5b600095505b83861015611194578035855260019590950194938601938601611176565b508096505050505050509250929050565b6000815180845260005b818110156111cb576020818501810151868301820152016111af565b818111156111dd576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061124560608301846111a5565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c0808401526112ab60e08401826111a5565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusSingleConsumerExampleABI = VRFV2PlusSingleConsumerExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go index 34108bea1dc..da32a6a202c 100644 --- a/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go +++ b/core/gethwrappers/generated/vrf_v2plus_sub_owner/vrf_v2plus_sub_owner.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusExternalSubOwnerExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"nativePayment\",\"type\":\"bool\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50604051610d77380380610d7783398101604081905261002f916101d0565b8133806000816100865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100b6576100b68161010a565b5050600280546001600160a01b039384166001600160a01b03199182161790915560038054958416958216959095179094555060048054929091169183169190911790556007805490911633179055610203565b6001600160a01b0381163314156101635760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161007d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146101cb57600080fd5b919050565b600080604083850312156101e357600080fd5b6101ec836101b4565b91506101fa602084016101b4565b90509250929050565b610b65806102126000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638ea9811711610076578063e89e106a1161005b578063e89e106a1461014f578063f2fde38b14610166578063f6eaffc81461017957600080fd5b80638ea981171461011c5780639eccacf61461012f57600080fd5b80631fe543e3146100a85780635b6c5de8146100bd57806379ba5097146100d05780638da5cb5b146100d8575b600080fd5b6100bb6100b6366004610902565b61018c565b005b6100bb6100cb3660046109f1565b610212565b6100bb610325565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100bb61012a366004610893565b610422565b6002546100f29073ffffffffffffffffffffffffffffffffffffffff1681565b61015860065481565b604051908152602001610113565b6100bb610174366004610893565b61052d565b6101586101873660046108d0565b610541565b60025473ffffffffffffffffffffffffffffffffffffffff163314610204576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61020e8282610562565b5050565b61021a6105e5565b60006040518060c001604052808481526020018881526020018661ffff1681526020018763ffffffff1681526020018563ffffffff16815260200161026e6040518060200160405280861515815250610668565b90526003546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906102c7908490600401610a69565b602060405180830381600087803b1580156102e157600080fd5b505af11580156102f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061031991906108e9565b60065550505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016101fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610462575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156104e6573361048760005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016101fb565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6105356105e5565b61053e81610724565b50565b6005818154811061055157600080fd5b600091825260209091200154905081565b60065482146105cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016101fb565b80516105e090600590602084019061081a565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101fb565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016106a191511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff81163314156107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610855579160200282015b8281111561085557825182559160200191906001019061083a565b50610861929150610865565b5090565b5b808211156108615760008155600101610866565b803563ffffffff8116811461088e57600080fd5b919050565b6000602082840312156108a557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146108c957600080fd5b9392505050565b6000602082840312156108e257600080fd5b5035919050565b6000602082840312156108fb57600080fd5b5051919050565b6000806040838503121561091557600080fd5b8235915060208084013567ffffffffffffffff8082111561093557600080fd5b818601915086601f83011261094957600080fd5b81358181111561095b5761095b610b29565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561099e5761099e610b29565b604052828152858101935084860182860187018b10156109bd57600080fd5b600095505b838610156109e05780358552600195909501949386019386016109c2565b508096505050505050509250929050565b60008060008060008060c08789031215610a0a57600080fd5b86359550610a1a6020880161087a565b9450604087013561ffff81168114610a3157600080fd5b9350610a3f6060880161087a565b92506080870135915060a08701358015158114610a5b57600080fd5b809150509295509295509295565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610ae05782810184015186820161010001528301610ac3565b81811115610af357600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x608060405234801561001057600080fd5b50604051610d68380380610d6883398101604081905261002f916101c1565b8133806000816100865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100b6576100b6816100fb565b5050600280546001600160a01b039384166001600160a01b031991821617909155600380549490931693811693909317909155506006805490911633179055506101f4565b6001600160a01b0381163314156101545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161007d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146101bc57600080fd5b919050565b600080604083850312156101d457600080fd5b6101dd836101a5565b91506101eb602084016101a5565b90509250929050565b610b65806102036000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80638ea9811711610076578063e89e106a1161005b578063e89e106a1461014f578063f2fde38b14610166578063f6eaffc81461017957600080fd5b80638ea981171461011c5780639eccacf61461012f57600080fd5b80631fe543e3146100a85780635b6c5de8146100bd57806379ba5097146100d05780638da5cb5b146100d8575b600080fd5b6100bb6100b6366004610902565b61018c565b005b6100bb6100cb3660046109f1565b610212565b6100bb610325565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100bb61012a366004610893565b610422565b6002546100f29073ffffffffffffffffffffffffffffffffffffffff1681565b61015860055481565b604051908152602001610113565b6100bb610174366004610893565b61052d565b6101586101873660046108d0565b610541565b60025473ffffffffffffffffffffffffffffffffffffffff163314610204576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b61020e8282610562565b5050565b61021a6105e5565b60006040518060c001604052808481526020018881526020018661ffff1681526020018763ffffffff1681526020018563ffffffff16815260200161026e6040518060200160405280861515815250610668565b90526002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e906102c7908490600401610a69565b602060405180830381600087803b1580156102e157600080fd5b505af11580156102f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061031991906108e9565b60055550505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016101fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610462575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156104e6573361048760005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015291831660248301529190911660448201526064016101fb565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6105356105e5565b61053e81610724565b50565b6004818154811061055157600080fd5b600091825260209091200154905081565b60055482146105cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265717565737420494420697320696e636f727265637400000000000000000060448201526064016101fb565b80516105e090600490602084019061081a565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016101fb565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016106a191511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff81163314156107a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016101fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610855579160200282015b8281111561085557825182559160200191906001019061083a565b50610861929150610865565b5090565b5b808211156108615760008155600101610866565b803563ffffffff8116811461088e57600080fd5b919050565b6000602082840312156108a557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146108c957600080fd5b9392505050565b6000602082840312156108e257600080fd5b5035919050565b6000602082840312156108fb57600080fd5b5051919050565b6000806040838503121561091557600080fd5b8235915060208084013567ffffffffffffffff8082111561093557600080fd5b818601915086601f83011261094957600080fd5b81358181111561095b5761095b610b29565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561099e5761099e610b29565b604052828152858101935084860182860187018b10156109bd57600080fd5b600095505b838610156109e05780358552600195909501949386019386016109c2565b508096505050505050509250929050565b60008060008060008060c08789031215610a0a57600080fd5b86359550610a1a6020880161087a565b9450604087013561ffff81168114610a3157600080fd5b9350610a3f6060880161087a565b92506080870135915060a08701358015158114610a5b57600080fd5b809150509295509295509295565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b81811015610ae05782810184015186820161010001528301610ac3565b81811115610af357600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169390930161010001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusExternalSubOwnerExampleABI = VRFV2PlusExternalSubOwnerExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go index 8d96b864642..852501d09ec 100644 --- a/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go +++ b/core/gethwrappers/generated/vrf_v2plus_upgraded_version/vrf_v2plus_upgraded_version.go @@ -66,8 +66,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV2PlusUpgradedVersionMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_provingKeys\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620060b9380380620060b9833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615ede620001db600039600081816104eb01526136f60152615ede6000f3fe6080604052600436106102015760003560e01c806201229114610206578063043bd6ae14610233578063088070f5146102575780630ae09540146102d757806315c48b84146102f957806318e3dd27146103215780631b6b6d2314610360578063294926571461038d578063294daa49146103ad578063330987b3146103c9578063405b84fa146103e957806340d6bb821461040957806341af6c87146104345780635d06b4ab1461046457806364d51a2a14610484578063659827441461049957806366316d8d146104b9578063689c4517146104d95780636b6feccc1461050d5780636f64f03f1461054357806372e9d5651461056357806379ba5097146105835780638402595e1461059857806386fe91c7146105b85780638da5cb5b146105d857806395b55cfc146105f65780639b1c385e146106095780639d40a6fd14610629578063a21a23e414610656578063a4c0ed361461066b578063aa433aff1461068b578063aefb212f146106ab578063b08c8795146106d8578063b2a7cac5146106f8578063bec4c08c14610718578063caf70c4a14610738578063cb63179714610758578063ce3f471914610778578063d98e620e1461078b578063da2f2610146107ab578063dac83d29146107e1578063dc311dd314610801578063e72f6e3014610832578063ee9d2d3814610852578063f2fde38b1461087f575b600080fd5b34801561021257600080fd5b5061021b61089f565b60405161022a939291906159d4565b60405180910390f35b34801561023f57600080fd5b5061024960115481565b60405190815260200161022a565b34801561026357600080fd5b50600d5461029f9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a00161022a565b3480156102e357600080fd5b506102f76102f2366004615655565b61091b565b005b34801561030557600080fd5b5061030e60c881565b60405161ffff909116815260200161022a565b34801561032d57600080fd5b50600a5461034890600160601b90046001600160601b031681565b6040516001600160601b03909116815260200161022a565b34801561036c57600080fd5b50600254610380906001600160a01b031681565b60405161022a9190615878565b34801561039957600080fd5b506102f76103a83660046151c7565b6109e9565b3480156103b957600080fd5b506040516001815260200161022a565b3480156103d557600080fd5b506103486103e43660046153c3565b610b66565b3480156103f557600080fd5b506102f7610404366004615655565b611041565b34801561041557600080fd5b5061041f6101f481565b60405163ffffffff909116815260200161022a565b34801561044057600080fd5b5061045461044f366004615305565b61142c565b604051901515815260200161022a565b34801561047057600080fd5b506102f761047f3660046151aa565b6115cd565b34801561049057600080fd5b5061030e606481565b3480156104a557600080fd5b506102f76104b43660046151fc565b611684565b3480156104c557600080fd5b506102f76104d43660046151c7565b6116e4565b3480156104e557600080fd5b506103807f000000000000000000000000000000000000000000000000000000000000000081565b34801561051957600080fd5b506012546105359063ffffffff80821691600160201b90041682565b60405161022a929190615b56565b34801561054f57600080fd5b506102f761055e366004615235565b6118ac565b34801561056f57600080fd5b50600354610380906001600160a01b031681565b34801561058f57600080fd5b506102f76119b3565b3480156105a457600080fd5b506102f76105b33660046151aa565b611a5d565b3480156105c457600080fd5b50600a54610348906001600160601b031681565b3480156105e457600080fd5b506000546001600160a01b0316610380565b6102f7610604366004615305565b611b69565b34801561061557600080fd5b506102496106243660046154a0565b611cad565b34801561063557600080fd5b50600754610649906001600160401b031681565b60405161022a9190615b6d565b34801561066257600080fd5b5061024961201d565b34801561067757600080fd5b506102f7610686366004615271565b61226b565b34801561069757600080fd5b506102f76106a6366004615305565b612408565b3480156106b757600080fd5b506106cb6106c636600461567a565b61246b565b60405161022a91906158ef565b3480156106e457600080fd5b506102f76106f33660046155b7565b61256c565b34801561070457600080fd5b506102f7610713366004615305565b6126e0565b34801561072457600080fd5b506102f7610733366004615655565b612804565b34801561074457600080fd5b506102496107533660046152cc565b61299b565b34801561076457600080fd5b506102f7610773366004615655565b6129cb565b6102f7610786366004615337565b612cb8565b34801561079757600080fd5b506102496107a6366004615305565b612fc9565b3480156107b757600080fd5b506103806107c6366004615305565b600e602052600090815260409020546001600160a01b031681565b3480156107ed57600080fd5b506102f76107fc366004615655565b612fea565b34801561080d57600080fd5b5061082161081c366004615305565b6130fa565b60405161022a959493929190615b81565b34801561083e57600080fd5b506102f761084d3660046151aa565b6131f5565b34801561085e57600080fd5b5061024961086d366004615305565b60106020526000908152604090205481565b34801561088b57600080fd5b506102f761089a3660046151aa565b6133d0565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561090957602002820191906000526020600020905b8154815260200190600101908083116108f5575b50505050509050925092509250909192565b60008281526005602052604090205482906001600160a01b03168061095357604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146109875780604051636c51fda960e11b815260040161097e9190615878565b60405180910390fd5b600d54600160301b900460ff16156109b25760405163769dd35360e11b815260040160405180910390fd5b6109bb8461142c565b156109d957604051631685ecdd60e31b815260040160405180910390fd5b6109e384846133e1565b50505050565b600d54600160301b900460ff1615610a145760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b0380831691161015610a5057604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290610a789084906001600160601b0316615d92565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610ac09190615d92565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610b3a576040519150601f19603f3d011682016040523d82523d6000602084013e610b3f565b606091505b5050905080610b615760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff1615610b945760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610ba5858561359c565b90506000846060015163ffffffff166001600160401b03811115610bcb57610bcb615e98565b604051908082528060200260200182016040528015610bf4578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610c6b57826040015181604051602001610c23929190615902565b6040516020818303038152906040528051906020012060001c828281518110610c4e57610c4e615e82565b602090810291909101015280610c6381615dea565b915050610bfa565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610ca391908690602401615a5e565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805460ff60301b1916600160301b179055908801516080890151919250600091610d089163ffffffff16908461380f565b600d805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316610d48816001615cfb565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a01518051610d9590600190615d7b565b81518110610da557610da5615e82565b602091010151600d5460f89190911c6001149150600090610dd6908a90600160581b900463ffffffff163a8561385d565b90508115610edf576020808c01516000908152600690915260409020546001600160601b03808316600160601b909204161015610e2657604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90610e5d908490600160601b90046001600160601b0316615d92565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c909152812080548594509092610eb691859116615d26565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610fcb565b6020808c01516000908152600690915260409020546001600160601b0380831691161015610f2057604051631e9acf1760e31b815260040160405180910390fd5b6020808c015160009081526006909152604081208054839290610f4d9084906001600160601b0316615d92565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b909152812080548594509092610fa691859116615d26565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051611028939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff161561106c5760405163769dd35360e11b815260040160405180910390fd5b611075816138ac565b6110945780604051635428d44960e01b815260040161097e9190615878565b6000806000806110a3866130fa565b945094505093509350336001600160a01b0316826001600160a01b0316146111065760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b604482015260640161097e565b61110f8661142c565b156111555760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b604482015260640161097e565b60006040518060c0016040528061116a600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016111be9190615941565b60405160208183030381529060405290506111d888613916565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b0388169061121190859060040161592e565b6000604051808303818588803b15801561122a57600080fd5b505af115801561123e573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611267905057506001600160601b03861615155b156113315760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061129e908a908a906004016158bf565b602060405180830381600087803b1580156112b857600080fd5b505af11580156112cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f091906152e8565b6113315760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b604482015260640161097e565b600d805460ff60301b1916600160301b17905560005b83518110156113da5783818151811061136257611362615e82565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016113959190615878565b600060405180830381600087803b1580156113af57600080fd5b505af11580156113c3573d6000803e3d6000fd5b5050505080806113d290615dea565b915050611347565b50600d805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be41879061141a9089908b9061588c565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287969395860193909291908301828280156114b657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611498575b505050505081525050905060005b8160400151518110156115c35760005b600f548110156115b0576000611579600f83815481106114f6576114f6615e82565b90600052602060002001548560400151858151811061151757611517615e82565b602002602001015188600460008960400151898151811061153a5761153a615e82565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613b64565b506000818152601060205260409020549091501561159d5750600195945050505050565b50806115a881615dea565b9150506114d4565b50806115bb81615dea565b9150506114c4565b5060009392505050565b6115d5613bed565b6115de816138ac565b156115fe578060405163ac8a27ef60e01b815260040161097e9190615878565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611679908390615878565b60405180910390a150565b61168c613bed565b6002546001600160a01b0316156116b657604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff161561170f5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03166117385760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b038083169116101561177457604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b60205260408120805483929061179c9084906001600160601b0316615d92565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166117e49190615d92565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061183990859085906004016158bf565b602060405180830381600087803b15801561185357600080fd5b505af1158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b91906152e8565b6118a857604051631e9acf1760e31b815260040160405180910390fd5b5050565b6118b4613bed565b6040805180820182526000916118e391908490600290839083908082843760009201919091525061299b915050565b6000818152600e60205260409020549091506001600160a01b03161561191f57604051634a0b8fa760e01b81526004810182905260240161097e565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8910160405180910390a2505050565b6001546001600160a01b03163314611a065760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b604482015260640161097e565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611a65613bed565b600a544790600160601b90046001600160601b031681811115611a9f5780826040516354ced18160e11b815260040161097e929190615902565b81811015610b61576000611ab38284615d7b565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611b02576040519150601f19603f3d011682016040523d82523d6000602084013e611b07565b606091505b5050905080611b295760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611b5a92919061588c565b60405180910390a15050505050565b600d54600160301b900460ff1615611b945760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611bc957604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611bf88385615d26565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611c409190615d26565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611c939190615ce3565b604051611ca1929190615902565b60405180910390a25050565b600d54600090600160301b900460ff1615611cdb5760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611d1657604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680611d63578260200135336040516379bfd40160e01b815260040161097e929190615a33565b600d5461ffff16611d7a606085016040860161559c565b61ffff161080611d9d575060c8611d97606085016040860161559c565b61ffff16115b15611dd757611db2606084016040850161559c565b600d5460405163539c34bb60e11b815261097e929161ffff169060c8906004016159b6565b600d5462010000900463ffffffff16611df6608085016060860161569c565b63ffffffff161115611e3c57611e12608084016060850161569c565b600d54604051637aebf00f60e11b815261097e929162010000900463ffffffff1690600401615b56565b6101f4611e4f60a085016080860161569c565b63ffffffff161115611e8957611e6b60a084016080850161569c565b6101f46040516311ce1afb60e21b815260040161097e929190615b56565b6000611e96826001615cfb565b9050600080611eac863533602089013586613b64565b90925090506000611ec8611ec360a0890189615bd6565b613c42565b90506000611ed582613cbf565b905083611ee0613d30565b60208a0135611ef560808c0160608d0161569c565b611f0560a08d0160808e0161569c565b3386604051602001611f1d9796959493929190615ab6565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611f94919061559c565b8e6060016020810190611fa7919061569c565b8f6080016020810190611fba919061569c565b89604051611fcd96959493929190615a77565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff161561204b5760405163769dd35360e11b815260040160405180910390fd5b600033612059600143615d7b565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b039091169060006120d383615e05565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561211257612112615e98565b60405190808252806020026020018201604052801561213b578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361221c9260028501920190614e1b565b5061222c91506008905083613dc9565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161225d9190615878565b60405180910390a250905090565b600d54600160301b900460ff16156122965760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b031633146122c1576040516344b0e3c360e01b815260040160405180910390fd5b602081146122e257604051638129bbcd60e01b815260040160405180910390fd5b60006122f082840184615305565b6000818152600560205260409020549091506001600160a01b031661232857604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061234f8385615d26565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166123979190615d26565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846123ea9190615ce3565b6040516123f8929190615902565b60405180910390a2505050505050565b612410613bed565b6000818152600560205260409020546001600160a01b031661244557604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020546124689082906001600160a01b03166133e1565b50565b606060006124796008613dd5565b905080841061249b57604051631390f2a160e01b815260040160405180910390fd5b60006124a78486615ce3565b9050818111806124b5575083155b6124bf57806124c1565b815b905060006124cf8683615d7b565b6001600160401b038111156124e6576124e6615e98565b60405190808252806020026020018201604052801561250f578160200160208202803683370190505b50905060005b81518110156125625761253361252b8883615ce3565b600890613ddf565b82828151811061254557612545615e82565b60209081029190910101528061255a81615dea565b915050612515565b5095945050505050565b612574613bed565b60c861ffff871611156125a157858660c860405163539c34bb60e11b815260040161097e939291906159b6565b600082136125c5576040516321ea67b360e11b81526004810183905260240161097e565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff1916881762010000870217600160301b600160781b031916600160381b850263ffffffff60581b191617600160581b83021790558a51601280548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff161561270b5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661274057604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612797576000818152600560205260409081902060010154905163d084e97560e01b815261097e916001600160a01b031690600401615878565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ca19185916158a5565b60008281526005602052604090205482906001600160a01b03168061283c57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146128675780604051636c51fda960e11b815260040161097e9190615878565b600d54600160301b900460ff16156128925760405163769dd35360e11b815260040160405180910390fd5b600084815260056020526040902060020154606414156128c5576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316156128fc576109e3565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e19061298d908690615878565b60405180910390a250505050565b6000816040516020016129ae91906158e1565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612a0357604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612a2e5780604051636c51fda960e11b815260040161097e9190615878565b600d54600160301b900460ff1615612a595760405163769dd35360e11b815260040160405180910390fd5b612a628461142c565b15612a8057604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612ace5783836040516379bfd40160e01b815260040161097e929190615a33565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612b3157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612b13575b50505050509050600060018251612b489190615d7b565b905060005b8251811015612c5457856001600160a01b0316838281518110612b7257612b72615e82565b60200260200101516001600160a01b03161415612c42576000838381518110612b9d57612b9d615e82565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612bcf57612bcf615e82565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255898152600590915260409020600201805480612c1a57612c1a615e6c565b600082815260209020810160001990810180546001600160a01b031916905501905550612c54565b80612c4c81615dea565b915050612b4d565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906123f8908890615878565b6000612cc6828401846154da565b9050806000015160ff16600114612cff57805160405163237d181f60e21b815260ff90911660048201526001602482015260440161097e565b8060a001516001600160601b03163414612d435760a08101516040516306acf13560e41b81523460048201526001600160601b03909116602482015260440161097e565b6020808201516000908152600590915260409020546001600160a01b031615612d7f576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612e1f5760016004600084606001518481518110612dab57612dab615e82565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008460200151815260200190815260200160002060006101000a8154816001600160401b0302191690836001600160401b031602179055508080612e1790615dea565b915050612d82565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612f1e92600285019290910190614e1b565b5050506080810151600a8054600090612f419084906001600160601b0316615d26565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612f8d9190615d26565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506109e381602001516008613dc990919063ffffffff16565b600f8181548110612fd957600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03168061302257604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461304d5780604051636c51fda960e11b815260040161097e9190615878565b600d54600160301b900460ff16156130785760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b038481169116146109e3576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19061298d90339087906158a5565b6000818152600560205260408120548190819081906060906001600160a01b031661313857604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156131db57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116131bd575b505050505090509450945094509450945091939590929450565b6131fd613bed565b6002546001600160a01b03166132265760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190613257903090600401615878565b60206040518083038186803b15801561326f57600080fd5b505afa158015613283573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a7919061531e565b600a549091506001600160601b0316818111156132db5780826040516354ced18160e11b815260040161097e929190615902565b81811015610b615760006132ef8284615d7b565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb90613322908790859060040161588c565b602060405180830381600087803b15801561333c57600080fd5b505af1158015613350573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337491906152e8565b61339157604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b43660084826040516133c292919061588c565b60405180910390a150505050565b6133d8613bed565b61246881613deb565b6000806133ed84613916565b60025491935091506001600160a01b03161580159061341457506001600160601b03821615155b156134c35760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906134549086906001600160601b0387169060040161588c565b602060405180830381600087803b15801561346e57600080fd5b505af1158015613482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a691906152e8565b6134c357604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613519576040519150601f19603f3d011682016040523d82523d6000602084013e61351e565b606091505b50509050806135405760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006135c8846000015161299b565b6000818152600e60205260409020549091506001600160a01b03168061360457604051631dfd6e1360e21b81526004810183905260240161097e565b600082866080015160405160200161361d929190615902565b60408051601f198184030181529181528151602092830120600081815260109093529120549091508061366357604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d01519351613692978a979096959101615b02565b6040516020818303038152906040528051906020012081146136c75760405163354a450b60e21b815260040160405180910390fd5b60006136d68760000151613e8f565b90508061379d578651604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d389161372a9190600401615b6d565b60206040518083038186803b15801561374257600080fd5b505afa158015613756573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377a919061531e565b90508061379d57865160405163175dadad60e01b815261097e9190600401615b6d565b60008860800151826040516020016137bf929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006137e68a83613f82565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a61138881101561382157600080fd5b61138881039050846040820482031161383957600080fd5b50823b61384557600080fd5b60008083516020850160008789f190505b9392505050565b6000811561388a576012546138839086908690600160201b900463ffffffff1686613fed565b90506138a4565b6012546138a1908690869063ffffffff1686614057565b90505b949350505050565b6000805b60135481101561390d57826001600160a01b0316601382815481106138d7576138d7615e82565b6000918252602090912001546001600160a01b031614156138fb5750600192915050565b8061390581615dea565b9150506138b0565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879687969495948601939192908301828280156139a257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613984575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613a7e576004600084604001518381518110613a2e57613a2e615e82565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b031916905580613a7681615dea565b915050613a07565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613ab66002830182614e80565b5050600085815260066020526040812055613ad2600886614144565b50600a8054859190600090613af19084906001600160601b0316615d92565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613b399190615d92565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613bc9918991849101615902565b60408051808303601f19018152919052805160209091012097909650945050505050565b6000546001600160a01b03163314613c405760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b604482015260640161097e565b565b60408051602081019091526000815281613c6b575060408051602081019091526000815261103b565b63125fa26760e31b613c7d8385615dba565b6001600160e01b03191614613ca557604051632923fee760e11b815260040160405180910390fd5b613cb28260048186615cb9565b8101906138569190615378565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613cf891511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b60004661a4b1811480613d45575062066eed81145b15613dc25760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613d8457600080fd5b505afa158015613d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dbc919061531e565b91505090565b4391505090565b60006138568383614150565b600061103b825490565b6000613856838361419f565b6001600160a01b038116331415613e3e5760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b604482015260640161097e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60004661a4b1811480613ea4575062066eed81145b80613eb1575062066eee81145b15613f7357610100836001600160401b0316613ecb613d30565b613ed59190615d7b565b1180613ef15750613ee4613d30565b836001600160401b031610155b15613eff5750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613f23908690600401615b6d565b60206040518083038186803b158015613f3b57600080fd5b505afa158015613f4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613856919061531e565b50506001600160401b03164090565b6000613fb68360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516141c9565b60038360200151604051602001613fce929190615a4a565b60408051601f1981840301815291905280516020909101209392505050565b600080613ff86143e4565b905060005a6140078888615ce3565b6140119190615d7b565b61401b9085615d5c565b9050600061403463ffffffff871664e8d4a51000615d5c565b9050826140418284615ce3565b61404b9190615ce3565b98975050505050505050565b600080614062614440565b905060008113614088576040516321ea67b360e11b81526004810182905260240161097e565b60006140926143e4565b9050600082825a6140a38b8b615ce3565b6140ad9190615d7b565b6140b79088615d5c565b6140c19190615ce3565b6140d390670de0b6b3a7640000615d5c565b6140dd9190615d48565b905060006140f663ffffffff881664e8d4a51000615d5c565b905061410d81676765c793fa10079d601b1b615d7b565b82111561412d5760405163e80fa38160e01b815260040160405180910390fd5b6141378183615ce3565b9998505050505050505050565b6000613856838361450b565b60008181526001830160205260408120546141975750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561103b565b50600061103b565b60008260000182815481106141b6576141b6615e82565b9060005260206000200154905092915050565b6141d2896145fe565b61421b5760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b604482015260640161097e565b614224886145fe565b6142685760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b604482015260640161097e565b614271836145fe565b6142bd5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e206375727665000000604482015260640161097e565b6142c6826145fe565b6143115760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b604482015260640161097e565b61431d878a88876146c1565b6143655760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b604482015260640161097e565b60006143718a876147d5565b90506000614384898b878b868989614839565b90506000614395838d8d8a8661494c565b9050808a146143d65760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b604482015260640161097e565b505050505050505050505050565b60004661a4b18114806143f9575062066eed81145b1561443857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613d8457600080fd5b600091505090565b600d5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561449e57600080fd5b505afa1580156144b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144d691906156b7565b5094509092508491505080156144fa57506144f18242615d7b565b8463ffffffff16105b156138a45750601154949350505050565b600081815260018301602052604081205480156145f457600061452f600183615d7b565b855490915060009061454390600190615d7b565b90508181146145a857600086600001828154811061456357614563615e82565b906000526020600020015490508087600001848154811061458657614586615e82565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806145b9576145b9615e6c565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061103b565b600091505061103b565b80516000906401000003d0191161464c5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b604482015260640161097e565b60208201516401000003d0191161469a5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b604482015260640161097e565b60208201516401000003d0199080096146ba8360005b602002015161498c565b1492915050565b60006001600160a01b0382166147075760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b604482015260640161097e565b60208401516000906001161561471e57601c614721565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe199182039250600091908909875160408051600080825260209091019182905292935060019161478b91869188918790615910565b6020604051602081039080840390855afa1580156147ad573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b6147dd614e9e565b61480a600184846040516020016147f693929190615857565b6040516020818303038152906040526149b0565b90505b614816816145fe565b61103b57805160408051602081019290925261483291016147f6565b905061480d565b614841614e9e565b825186516401000003d01990819006910614156148a05760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e63740000604482015260640161097e565b6148ab8789886149fe565b6148f05760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b604482015260640161097e565b6148fb8486856149fe565b6149415760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b604482015260640161097e565b61404b868484614b19565b60006002868686858760405160200161496a969594939291906157fd565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b6149b8614e9e565b6149c182614bdc565b81526149d66149d18260006146b0565b614c17565b602082018190526002900660011415612018576020810180516401000003d019039052919050565b600082614a3b5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b604482015260640161097e565b83516020850151600090614a5190600290615e2c565b15614a5d57601c614a60565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614aa3908390869088908790615910565b6020604051602081039080840390855afa158015614ac5573d6000803e3d6000fd5b505050602060405103519050600086604051602001614ae491906157eb565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614b21614e9e565b835160208086015185519186015160009384938493614b4293909190614c37565b919450925090506401000003d019858209600114614b9e5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b604482015260640161097e565b60405180604001604052806401000003d01980614bbd57614bbd615e56565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061201857604080516020808201939093528151808203840181529082019091528051910120614be4565b600061103b826002614c306401000003d0196001615ce3565b901c614d17565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614c7783838585614dae565b9098509050614c8888828e88614dd2565b9098509050614c9988828c87614dd2565b90985090506000614cac8d878b85614dd2565b9098509050614cbd88828686614dae565b9098509050614cce88828e89614dd2565b9098509050818114614d03576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614d07565b8196505b5050505050509450945094915050565b600080614d22614ebc565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614d54614eda565b60208160c0846005600019fa925082614da45760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b604482015260640161097e565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614e70579160200282015b82811115614e7057825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614e3b565b50614e7c929150614ef8565b5090565b50805460008255906000526020600020908101906124689190614ef8565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614e7c5760008155600101614ef9565b803561201881615eae565b600082601f830112614f2957600080fd5b813560206001600160401b03821115614f4457614f44615e98565b8160051b614f53828201615c89565b838152828101908684018388018501891015614f6e57600080fd5b600093505b85841015614f9a578035614f8681615eae565b835260019390930192918401918401614f73565b50979650505050505050565b600082601f830112614fb757600080fd5b614fbf615c1c565b808385604086011115614fd157600080fd5b60005b6002811015614ff3578135845260209384019390910190600101614fd4565b509095945050505050565b60008083601f84011261501057600080fd5b5081356001600160401b0381111561502757600080fd5b60208301915083602082850101111561503f57600080fd5b9250929050565b600082601f83011261505757600080fd5b81356001600160401b0381111561507057615070615e98565b615083601f8201601f1916602001615c89565b81815284602083860101111561509857600080fd5b816020850160208301376000918101602001919091529392505050565b600060c082840312156150c757600080fd5b6150cf615c44565b905081356001600160401b0380821682146150e957600080fd5b8183526020840135602084015261510260408501615168565b604084015261511360608501615168565b606084015261512460808501614f0d565b608084015260a084013591508082111561513d57600080fd5b5061514a84828501615046565b60a08301525092915050565b803561ffff8116811461201857600080fd5b803563ffffffff8116811461201857600080fd5b80516001600160501b038116811461201857600080fd5b80356001600160601b038116811461201857600080fd5b6000602082840312156151bc57600080fd5b813561385681615eae565b600080604083850312156151da57600080fd5b82356151e581615eae565b91506151f360208401615193565b90509250929050565b6000806040838503121561520f57600080fd5b823561521a81615eae565b9150602083013561522a81615eae565b809150509250929050565b6000806060838503121561524857600080fd5b823561525381615eae565b91506060830184101561526557600080fd5b50926020919091019150565b6000806000806060858703121561528757600080fd5b843561529281615eae565b93506020850135925060408501356001600160401b038111156152b457600080fd5b6152c087828801614ffe565b95989497509550505050565b6000604082840312156152de57600080fd5b6138568383614fa6565b6000602082840312156152fa57600080fd5b815161385681615ec3565b60006020828403121561531757600080fd5b5035919050565b60006020828403121561533057600080fd5b5051919050565b6000806020838503121561534a57600080fd5b82356001600160401b0381111561536057600080fd5b61536c85828601614ffe565b90969095509350505050565b60006020828403121561538a57600080fd5b604051602081016001600160401b03811182821017156153ac576153ac615e98565b60405282356153ba81615ec3565b81529392505050565b6000808284036101c08112156153d857600080fd5b6101a0808212156153e857600080fd5b6153f0615c66565b91506153fc8686614fa6565b825261540b8660408701614fa6565b60208301526080850135604083015260a0850135606083015260c0850135608083015261543a60e08601614f0d565b60a083015261010061544e87828801614fa6565b60c0840152615461876101408801614fa6565b60e0840152610180860135908301529092508301356001600160401b0381111561548a57600080fd5b615496858286016150b5565b9150509250929050565b6000602082840312156154b257600080fd5b81356001600160401b038111156154c857600080fd5b820160c0818503121561385657600080fd5b6000602082840312156154ec57600080fd5b81356001600160401b038082111561550357600080fd5b9083019060c0828603121561551757600080fd5b61551f615c44565b823560ff8116811461553057600080fd5b81526020838101359082015261554860408401614f0d565b604082015260608301358281111561555f57600080fd5b61556b87828601614f18565b60608301525061557d60808401615193565b608082015261558e60a08401615193565b60a082015295945050505050565b6000602082840312156155ae57600080fd5b61385682615156565b60008060008060008086880360e08112156155d157600080fd5b6155da88615156565b96506155e860208901615168565b95506155f660408901615168565b945061560460608901615168565b9350608088013592506040609f198201121561561f57600080fd5b50615628615c1c565b61563460a08901615168565b815261564260c08901615168565b6020820152809150509295509295509295565b6000806040838503121561566857600080fd5b82359150602083013561522a81615eae565b6000806040838503121561568d57600080fd5b50508035926020909101359150565b6000602082840312156156ae57600080fd5b61385682615168565b600080600080600060a086880312156156cf57600080fd5b6156d88661517c565b94506020860151935060408601519250606086015191506156fb6080870161517c565b90509295509295909350565b600081518084526020808501945080840160005b838110156157405781516001600160a01b03168752958201959082019060010161571b565b509495945050505050565b8060005b60028110156109e357815184526020938401939091019060010161574f565b600081518084526020808501945080840160005b8381101561574057815187529582019590820190600101615782565b6000815180845260005b818110156157c4576020818501810151868301820152016157a8565b818111156157d6576000602083870101525b50601f01601f19169290920160200192915050565b6157f5818361574b565b604001919050565b86815261580d602082018761574b565b61581a606082018661574b565b61582760a082018561574b565b61583460e082018461574b565b60609190911b6001600160601b0319166101208201526101340195945050505050565b838152615867602082018461574b565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b6040810161103b828461574b565b602081526000613856602083018461576e565b918252602082015260400190565b93845260ff9290921660208401526040830152606082015260800190565b602081526000613856602083018461579e565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261598660e0840182615707565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b61ffff93841681529183166020830152909116604082015260600190565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615a2557845183529383019391830191600101615a09565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b82815260608101613856602083018461574b565b8281526040602082015260006138a4604083018461576e565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261404b60c083018461579e565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906141379083018461579e565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906141379083018461579e565b63ffffffff92831681529116602082015260400190565b6001600160401b0391909116815260200190565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615bcb90830184615707565b979650505050505050565b6000808335601e19843603018112615bed57600080fd5b8301803591506001600160401b03821115615c0757600080fd5b60200191503681900382131561503f57600080fd5b604080519081016001600160401b0381118282101715615c3e57615c3e615e98565b60405290565b60405160c081016001600160401b0381118282101715615c3e57615c3e615e98565b60405161012081016001600160401b0381118282101715615c3e57615c3e615e98565b604051601f8201601f191681016001600160401b0381118282101715615cb157615cb1615e98565b604052919050565b60008085851115615cc957600080fd5b83861115615cd657600080fd5b5050820193919092039150565b60008219821115615cf657615cf6615e40565b500190565b60006001600160401b03828116848216808303821115615d1d57615d1d615e40565b01949350505050565b60006001600160601b03828116848216808303821115615d1d57615d1d615e40565b600082615d5757615d57615e56565b500490565b6000816000190483118215151615615d7657615d76615e40565b500290565b600082821015615d8d57615d8d615e40565b500390565b60006001600160601b0383811690831681811015615db257615db2615e40565b039392505050565b6001600160e01b03198135818116916004851015615de25780818660040360031b1b83161692505b505092915050565b6000600019821415615dfe57615dfe615e40565b5060010190565b60006001600160401b0382811680821415615e2257615e22615e40565b6001019392505050565b600082615e3b57615e3b615e56565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461246857600080fd5b801515811461246857600080fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"internalBalance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"externalBalance\",\"type\":\"uint256\"}],\"name\":\"BalanceInvariantViolated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNum\",\"type\":\"uint256\"}],\"name\":\"BlockhashNotInStore\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorNotRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"transferredValue\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"expectedValue\",\"type\":\"uint96\"}],\"name\":\"InvalidNativeBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"have\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"min\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"max\",\"type\":\"uint16\"}],\"name\":\"InvalidRequestConfirmations\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"requestVersion\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"expectedVersion\",\"type\":\"uint8\"}],\"name\":\"InvalidVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkNotSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeRequestedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoCorrespondingRequest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"NoSuchProvingKey\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"NumWordsTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PendingRequestExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"ProvingKeyAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Reentrant\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubscriptionIDCollisionFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"MigrationCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NativeFundsRecovered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subID\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"RandomWordsFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountLink\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountNative\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldNativeBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newNativeBalance\",\"type\":\"uint256\"}],\"name\":\"SubscriptionFundedWithNative\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BLOCKHASH_STORE\",\"outputs\":[{\"internalType\":\"contractBlockhashStoreInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_NATIVE_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CONSUMERS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_NUM_WORDS\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_REQUEST_CONFIRMATIONS\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256[2]\",\"name\":\"pk\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"gamma\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"s\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"uWitness\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"cGammaWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"sHashWitness\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"zInv\",\"type\":\"uint256\"}],\"internalType\":\"structVRF.Proof\",\"name\":\"proof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"fundSubscriptionWithNative\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"getActiveSubscriptionIds\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRequestConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicKey\",\"type\":\"uint256[2]\"}],\"name\":\"hashOfKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrationVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedData\",\"type\":\"bytes\"}],\"name\":\"onMigration\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverNativeFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"registerMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structVRFV2PlusClient.RandomWordsRequest\",\"name\":\"req\",\"type\":\"tuple\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_config\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"reentrancyLock\",\"type\":\"bool\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_currentSubNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_provingKeyHashes\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_totalNativeBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLINKAndLINKNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620061a6380380620061a6833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615fcb620001db600039600081816104a601526136530152615fcb6000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae095401461029257806315c48b84146102b457806318e3dd27146102dc5780631b6b6d231461031b5780632949265714610348578063294daa4914610368578063330987b314610384578063405b84fa146103a457806340d6bb82146103c457806341af6c87146103ef5780635d06b4ab1461041f57806364d51a2a1461043f578063659827441461045457806366316d8d14610474578063689c4517146104945780636f64f03f146104c857806372e9d565146104e857806379ba5097146105085780638402595e1461051d57806386fe91c71461053d5780638da5cb5b1461055d57806395b55cfc1461057b5780639b1c385e1461058e5780639d40a6fd146105bc578063a21a23e4146105e9578063a4c0ed36146105fe578063aa433aff1461061e578063aefb212f1461063e578063b08c87951461066b578063b2a7cac51461068b578063bec4c08c146106ab578063caf70c4a146106cb578063cb631797146106eb578063ce3f47191461070b578063d98e620e1461071e578063dac83d291461073e578063dc311dd31461075e578063e72f6e301461078f578063ee9d2d38146107af578063f2fde38b146107dc575b600080fd5b3480156101f157600080fd5b506101fa6107fc565b60405161020993929190615a56565b60405180910390f35b34801561021e57600080fd5b50600d5461025a9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610209565b34801561029e57600080fd5b506102b26102ad3660046156c9565b610878565b005b3480156102c057600080fd5b506102c960c881565b60405161ffff9091168152602001610209565b3480156102e857600080fd5b50600a5461030390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561032757600080fd5b5060025461033b906001600160a01b031681565b60405161020991906158fa565b34801561035457600080fd5b506102b261036336600461523b565b610946565b34801561037457600080fd5b5060405160028152602001610209565b34801561039057600080fd5b5061030361039f36600461541e565b610ac3565b3480156103b057600080fd5b506102b26103bf3660046156c9565b610f9e565b3480156103d057600080fd5b506103da6101f481565b60405163ffffffff9091168152602001610209565b3480156103fb57600080fd5b5061040f61040a3660046156b0565b611389565b6040519015158152602001610209565b34801561042b57600080fd5b506102b261043a36600461521e565b61152a565b34801561044b57600080fd5b506102c9606481565b34801561046057600080fd5b506102b261046f366004615270565b6115e1565b34801561048057600080fd5b506102b261048f36600461523b565b611641565b3480156104a057600080fd5b5061033b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d457600080fd5b506102b26104e33660046152a9565b611809565b3480156104f457600080fd5b5060035461033b906001600160a01b031681565b34801561051457600080fd5b506102b2611910565b34801561052957600080fd5b506102b261053836600461521e565b6119ba565b34801561054957600080fd5b50600a54610303906001600160601b031681565b34801561056957600080fd5b506000546001600160a01b031661033b565b6102b26105893660046156b0565b611ac6565b34801561059a57600080fd5b506105ae6105a93660046154fb565b611c0a565b604051908152602001610209565b3480156105c857600080fd5b506007546105dc906001600160401b031681565b6040516102099190615bef565b3480156105f557600080fd5b506105ae611f7a565b34801561060a57600080fd5b506102b26106193660046152e5565b6121c8565b34801561062a57600080fd5b506102b26106393660046156b0565b612365565b34801561064a57600080fd5b5061065e6106593660046156ee565b6123c8565b6040516102099190615971565b34801561067757600080fd5b506102b2610686366004615612565b6124c9565b34801561069757600080fd5b506102b26106a63660046156b0565b61263d565b3480156106b757600080fd5b506102b26106c63660046156c9565b612761565b3480156106d757600080fd5b506105ae6106e6366004615340565b6128f8565b3480156106f757600080fd5b506102b26107063660046156c9565b612928565b6102b2610719366004615392565b612c15565b34801561072a57600080fd5b506105ae6107393660046156b0565b612f26565b34801561074a57600080fd5b506102b26107593660046156c9565b612f47565b34801561076a57600080fd5b5061077e6107793660046156b0565b613057565b604051610209959493929190615c03565b34801561079b57600080fd5b506102b26107aa36600461521e565b613152565b3480156107bb57600080fd5b506105ae6107ca3660046156b0565b60106020526000908152604090205481565b3480156107e857600080fd5b506102b26107f736600461521e565b61332d565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561086657602002820191906000526020600020905b815481526020019060010190808311610852575b50505050509050925092509250909192565b60008281526005602052604090205482906001600160a01b0316806108b057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146108e45780604051636c51fda960e11b81526004016108db91906158fa565b60405180910390fd5b600d54600160301b900460ff161561090f5760405163769dd35360e11b815260040160405180910390fd5b61091884611389565b1561093657604051631685ecdd60e31b815260040160405180910390fd5b610940848461333e565b50505050565b600d54600160301b900460ff16156109715760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156109ad57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c6020526040812080548392906109d59084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610a1d9190615e0b565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a97576040519150601f19603f3d011682016040523d82523d6000602084013e610a9c565b606091505b5050905080610abe5760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff1615610af15760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610b0285856134f9565b90506000846060015163ffffffff166001600160401b03811115610b2857610b28615f3d565b604051908082528060200260200182016040528015610b51578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610bc857826040015181604051602001610b80929190615984565b6040516020818303038152906040528051906020012060001c828281518110610bab57610bab615f27565b602090810291909101015280610bc081615e8f565b915050610b57565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610c0091908690602401615ae0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805460ff60301b1916600160301b179055908801516080890151919250600091610c659163ffffffff16908461376c565b600d805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316610ca5816001615d7d565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a01518051610cf290600190615df4565b81518110610d0257610d02615f27565b602091010151600d5460f89190911c6001149150600090610d33908a90600160581b900463ffffffff163a856137ba565b90508115610e3c576020808c01516000908152600690915260409020546001600160601b03808316600160601b909204161015610d8357604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90610dba908490600160601b90046001600160601b0316615e0b565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c909152812080548594509092610e1391859116615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610f28565b6020808c01516000908152600690915260409020546001600160601b0380831691161015610e7d57604051631e9acf1760e31b815260040160405180910390fd5b6020808c015160009081526006909152604081208054839290610eaa9084906001600160601b0316615e0b565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b909152812080548594509092610f0391859116615d9f565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610f85939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff1615610fc95760405163769dd35360e11b815260040160405180910390fd5b610fd281613809565b610ff15780604051635428d44960e01b81526004016108db91906158fa565b60008060008061100086613057565b945094505093509350336001600160a01b0316826001600160a01b0316146110635760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b60448201526064016108db565b61106c86611389565b156110b25760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b60448201526064016108db565b60006040518060c001604052806110c7600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161111b91906159c3565b604051602081830303815290604052905061113588613873565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b0388169061116e9085906004016159b0565b6000604051808303818588803b15801561118757600080fd5b505af115801561119b573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506111c4905057506001600160601b03861615155b1561128e5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906111fb908a908a90600401615941565b602060405180830381600087803b15801561121557600080fd5b505af1158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d919061535c565b61128e5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b60448201526064016108db565b600d805460ff60301b1916600160301b17905560005b8351811015611337578381815181106112bf576112bf615f27565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016112f291906158fa565b600060405180830381600087803b15801561130c57600080fd5b505af1158015611320573d6000803e3d6000fd5b50505050808061132f90615e8f565b9150506112a4565b50600d805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906113779089908b9061590e565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561141357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113f5575b505050505081525050905060005b8160400151518110156115205760005b600f5481101561150d5760006114d6600f838154811061145357611453615f27565b90600052602060002001548560400151858151811061147457611474615f27565b602002602001015188600460008960400151898151811061149757611497615f27565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613ac1565b50600081815260106020526040902054909150156114fa5750600195945050505050565b508061150581615e8f565b915050611431565b508061151881615e8f565b915050611421565b5060009392505050565b611532613b4a565b61153b81613809565b1561155b578060405163ac8a27ef60e01b81526004016108db91906158fa565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af01625906115d69083906158fa565b60405180910390a150565b6115e9613b4a565b6002546001600160a01b03161561161357604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff161561166c5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03166116955760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b03808316911610156116d157604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b6020526040812080548392906116f99084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166117419190615e0b565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906117969085908590600401615941565b602060405180830381600087803b1580156117b057600080fd5b505af11580156117c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e8919061535c565b61180557604051631e9acf1760e31b815260040160405180910390fd5b5050565b611811613b4a565b6040805180820182526000916118409190849060029083908390808284376000920191909152506128f8915050565b6000818152600e60205260409020549091506001600160a01b03161561187c57604051634a0b8fa760e01b8152600481018290526024016108db565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8910160405180910390a2505050565b6001546001600160a01b031633146119635760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b60448201526064016108db565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6119c2613b4a565b600a544790600160601b90046001600160601b0316818111156119fc5780826040516354ced18160e11b81526004016108db929190615984565b81811015610abe576000611a108284615df4565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611a5f576040519150601f19603f3d011682016040523d82523d6000602084013e611a64565b606091505b5050905080611a865760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611ab792919061590e565b60405180910390a15050505050565b600d54600160301b900460ff1615611af15760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611b2657604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611b558385615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611b9d9190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611bf09190615d65565b604051611bfe929190615984565b60405180910390a25050565b600d54600090600160301b900460ff1615611c385760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611c7357604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680611cc0578260200135336040516379bfd40160e01b81526004016108db929190615ab5565b600d5461ffff16611cd760608501604086016155f7565b61ffff161080611cfa575060c8611cf460608501604086016155f7565b61ffff16115b15611d3457611d0f60608401604085016155f7565b600d5460405163539c34bb60e11b81526108db929161ffff169060c890600401615a38565b600d5462010000900463ffffffff16611d536080850160608601615710565b63ffffffff161115611d9957611d6f6080840160608501615710565b600d54604051637aebf00f60e11b81526108db929162010000900463ffffffff1690600401615bd8565b6101f4611dac60a0850160808601615710565b63ffffffff161115611de657611dc860a0840160808501615710565b6101f46040516311ce1afb60e21b81526004016108db929190615bd8565b6000611df3826001615d7d565b9050600080611e09863533602089013586613ac1565b90925090506000611e25611e2060a0890189615c58565b613b9f565b90506000611e3282613c1c565b905083611e3d613c8d565b60208a0135611e5260808c0160608d01615710565b611e6260a08d0160808e01615710565b3386604051602001611e7a9796959493929190615b38565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611ef191906155f7565b8e6060016020810190611f049190615710565b8f6080016020810190611f179190615710565b89604051611f2a96959493929190615af9565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff1615611fa85760405163769dd35360e11b815260040160405180910390fd5b600033611fb6600143615df4565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061203083615eaa565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561206f5761206f615f3d565b604051908082528060200260200182016040528015612098578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b0392831617835592516001830180549094169116179091559251805194955090936121799260028501920190614e8f565b5061218991506008905083613d1d565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d336040516121ba91906158fa565b60405180910390a250905090565b600d54600160301b900460ff16156121f35760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316331461221e576040516344b0e3c360e01b815260040160405180910390fd5b6020811461223f57604051638129bbcd60e01b815260040160405180910390fd5b600061224d828401846156b0565b6000818152600560205260409020549091506001600160a01b031661228557604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906122ac8385615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166122f49190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846123479190615d65565b604051612355929190615984565b60405180910390a2505050505050565b61236d613b4a565b6000818152600560205260409020546001600160a01b03166123a257604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020546123c59082906001600160a01b031661333e565b50565b606060006123d66008613d29565b90508084106123f857604051631390f2a160e01b815260040160405180910390fd5b60006124048486615d65565b905081811180612412575083155b61241c578061241e565b815b9050600061242c8683615df4565b6001600160401b0381111561244357612443615f3d565b60405190808252806020026020018201604052801561246c578160200160208202803683370190505b50905060005b81518110156124bf576124906124888883615d65565b600890613d33565b8282815181106124a2576124a2615f27565b6020908102919091010152806124b781615e8f565b915050612472565b5095945050505050565b6124d1613b4a565b60c861ffff871611156124fe57858660c860405163539c34bb60e11b81526004016108db93929190615a38565b60008213612522576040516321ea67b360e11b8152600481018390526024016108db565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff1916881762010000870217600160301b600160781b031916600160381b850263ffffffff60581b191617600160581b83021790558a51601280548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff16156126685760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661269d57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b031633146126f4576000818152600560205260409081902060010154905163d084e97560e01b81526108db916001600160a01b0316906004016158fa565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611bfe918591615927565b60008281526005602052604090205482906001600160a01b03168061279957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146127c45780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff16156127ef5760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612822576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b03161561285957610940565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1906128ea9086906158fa565b60405180910390a250505050565b60008160405160200161290b9190615963565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b03168061296057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461298b5780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff16156129b65760405163769dd35360e11b815260040160405180910390fd5b6129bf84611389565b156129dd57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612a2b5783836040516379bfd40160e01b81526004016108db929190615ab5565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612a8e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a70575b50505050509050600060018251612aa59190615df4565b905060005b8251811015612bb157856001600160a01b0316838281518110612acf57612acf615f27565b60200260200101516001600160a01b03161415612b9f576000838381518110612afa57612afa615f27565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612b2c57612b2c615f27565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255898152600590915260409020600201805480612b7757612b77615f11565b600082815260209020810160001990810180546001600160a01b031916905501905550612bb1565b80612ba981615e8f565b915050612aaa565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906123559088906158fa565b6000612c2382840184615535565b9050806000015160ff16600114612c5c57805160405163237d181f60e21b815260ff9091166004820152600160248201526044016108db565b8060a001516001600160601b03163414612ca05760a08101516040516306acf13560e41b81523460048201526001600160601b0390911660248201526044016108db565b6020808201516000908152600590915260409020546001600160a01b031615612cdc576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612d7c5760016004600084606001518481518110612d0857612d08615f27565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008460200151815260200190815260200160002060006101000a8154816001600160401b0302191690836001600160401b031602179055508080612d7490615e8f565b915050612cdf565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612e7b92600285019290910190614e8f565b5050506080810151600a8054600090612e9e9084906001600160601b0316615d9f565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612eea9190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555061094081602001516008613d1d90919063ffffffff16565b600f8181548110612f3657600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b031680612f7f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612faa5780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff1615612fd55760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610940576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a1906128ea9033908790615927565b6000818152600560205260408120548190819081906060906001600160a01b031661309557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b039094169391839183018282801561313857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161311a575b505050505090509450945094509450945091939590929450565b61315a613b4a565b6002546001600160a01b03166131835760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906131b49030906004016158fa565b60206040518083038186803b1580156131cc57600080fd5b505afa1580156131e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132049190615379565b600a549091506001600160601b0316818111156132385780826040516354ced18160e11b81526004016108db929190615984565b81811015610abe57600061324c8284615df4565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061327f908790859060040161590e565b602060405180830381600087803b15801561329957600080fd5b505af11580156132ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d1919061535c565b6132ee57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161331f92919061590e565b60405180910390a150505050565b613335613b4a565b6123c581613d3f565b60008061334a84613873565b60025491935091506001600160a01b03161580159061337157506001600160601b03821615155b156134205760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906133b19086906001600160601b0387169060040161590e565b602060405180830381600087803b1580156133cb57600080fd5b505af11580156133df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613403919061535c565b61342057604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613476576040519150601f19603f3d011682016040523d82523d6000602084013e61347b565b606091505b505090508061349d5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b6040805160608101825260008082526020820181905291810191909152600061352584600001516128f8565b6000818152600e60205260409020549091506001600160a01b03168061356157604051631dfd6e1360e21b8152600481018390526024016108db565b600082866080015160405160200161357a929190615984565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806135c057604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516135ef978a979096959101615b84565b6040516020818303038152906040528051906020012081146136245760405163354a450b60e21b815260040160405180910390fd5b60006136338760000151613de3565b9050806136fa578651604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d38916136879190600401615bef565b60206040518083038186803b15801561369f57600080fd5b505afa1580156136b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d79190615379565b9050806136fa57865160405163175dadad60e01b81526108db9190600401615bef565b600088608001518260405160200161371c929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006137438a83613ec0565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a61138881101561377e57600080fd5b61138881039050846040820482031161379657600080fd5b50823b6137a257600080fd5b60008083516020850160008789f190505b9392505050565b600081156137e7576012546137e09086908690600160201b900463ffffffff1686613f2b565b9050613801565b6012546137fe908690869063ffffffff1686613fcd565b90505b949350505050565b6000805b60135481101561386a57826001600160a01b03166013828154811061383457613834615f27565b6000918252602090912001546001600160a01b031614156138585750600192915050565b8061386281615e8f565b91505061380d565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879687969495948601939192908301828280156138ff57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116138e1575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b8260400151518110156139db57600460008460400151838151811061398b5761398b615f27565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b0319169055806139d381615e8f565b915050613964565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613a136002830182614ef4565b5050600085815260066020526040812055613a2f6008866140f2565b50600a8054859190600090613a4e9084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613a969190615e0b565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613b26918991849101615984565b60408051808303601f19018152919052805160209091012097909650945050505050565b6000546001600160a01b03163314613b9d5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b60448201526064016108db565b565b60408051602081019091526000815281613bc85750604080516020810190915260008152610f98565b63125fa26760e31b613bda8385615e33565b6001600160e01b03191614613c0257604051632923fee760e11b815260040160405180910390fd5b613c0f8260048186615d3b565b8101906137b391906153d3565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613c5591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613c99816140fe565b15613d165760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cd857600080fd5b505afa158015613cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d109190615379565b91505090565b4391505090565b60006137b38383614121565b6000610f98825490565b60006137b38383614170565b6001600160a01b038116331415613d925760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b60448201526064016108db565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613def816140fe565b15613eb157610100836001600160401b0316613e09613c8d565b613e139190615df4565b1180613e2f5750613e22613c8d565b836001600160401b031610155b15613e3d5750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613e61908690600401615bef565b60206040518083038186803b158015613e7957600080fd5b505afa158015613e8d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b39190615379565b50506001600160401b03164090565b6000613ef48360000151846020015185604001518660600151868860a001518960c001518a60e001518b610100015161419a565b60038360200151604051602001613f0c929190615acc565b60408051601f1981840301815291905280516020909101209392505050565b600080613f6e6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506143b592505050565b905060005a613f7d8888615d65565b613f879190615df4565b613f919085615dd5565b90506000613faa63ffffffff871664e8d4a51000615dd5565b905082613fb78284615d65565b613fc19190615d65565b98975050505050505050565b600080613fd861447a565b905060008113613ffe576040516321ea67b360e11b8152600481018290526024016108db565b60006140406000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506143b592505050565b9050600082825a6140518b8b615d65565b61405b9190615df4565b6140659088615dd5565b61406f9190615d65565b61408190670de0b6b3a7640000615dd5565b61408b9190615dc1565b905060006140a463ffffffff881664e8d4a51000615dd5565b90506140bb81676765c793fa10079d601b1b615df4565b8211156140db5760405163e80fa38160e01b815260040160405180910390fd5b6140e58183615d65565b9998505050505050505050565b60006137b38383614545565b600061a4b1821480614112575062066eed82145b80610f9857505062066eee1490565b600081815260018301602052604081205461416857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610f98565b506000610f98565b600082600001828154811061418757614187615f27565b9060005260206000200154905092915050565b6141a389614638565b6141ec5760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b60448201526064016108db565b6141f588614638565b6142395760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b60448201526064016108db565b61424283614638565b61428e5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108db565b61429782614638565b6142e25760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b60448201526064016108db565b6142ee878a88876146fb565b6143365760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b60448201526064016108db565b60006143428a8761480f565b90506000614355898b878b868989614873565b90506000614366838d8d8a86614986565b9050808a146143a75760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b60448201526064016108db565b505050505050505050505050565b6000466143c1816140fe565b1561440057606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7957600080fd5b614409816149c6565b1561386a57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615f776048913960405160200161444f929190615850565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e6191906159b0565b600d5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b1580156144d857600080fd5b505afa1580156144ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614510919061572b565b509450909250849150508015614534575061452b8242615df4565b8463ffffffff16105b156138015750601154949350505050565b6000818152600183016020526040812054801561462e576000614569600183615df4565b855490915060009061457d90600190615df4565b90508181146145e257600086600001828154811061459d5761459d615f27565b90600052602060002001549050808760000184815481106145c0576145c0615f27565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806145f3576145f3615f11565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610f98565b6000915050610f98565b80516000906401000003d019116146865760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d019116146d45760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d0199080096146f48360005b6020020151614a00565b1492915050565b60006001600160a01b0382166147415760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b60448201526064016108db565b60208401516000906001161561475857601c61475b565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020909101918290529293506001916147c591869188918790615992565b6020604051602081039080840390855afa1580156147e7573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614817614f12565b61484460018484604051602001614830939291906158d9565b604051602081830303815290604052614a24565b90505b61485081614638565b610f9857805160408051602081019290925261486c9101614830565b9050614847565b61487b614f12565b825186516401000003d01990819006910614156148da5760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108db565b6148e5878988614a72565b61492a5760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b60448201526064016108db565b614935848685614a72565b61497b5760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b60448201526064016108db565b613fc1868484614b8d565b6000600286868685876040516020016149a49695949392919061587f565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a8214806149d857506101a482145b806149e5575062aa37dc82145b806149f1575061210582145b80610f9857505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614a2c614f12565b614a3582614c50565b8152614a4a614a458260006146ea565b614c8b565b602082018190526002900660011415611f75576020810180516401000003d019039052919050565b600082614aaf5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b60448201526064016108db565b83516020850151600090614ac590600290615ed1565b15614ad157601c614ad4565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614b17908390869088908790615992565b6020604051602081039080840390855afa158015614b39573d6000803e3d6000fd5b505050602060405103519050600086604051602001614b58919061583e565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614b95614f12565b835160208086015185519186015160009384938493614bb693909190614cab565b919450925090506401000003d019858209600114614c125760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b60448201526064016108db565b60405180604001604052806401000003d01980614c3157614c31615efb565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611f7557604080516020808201939093528151808203840181529082019091528051910120614c58565b6000610f98826002614ca46401000003d0196001615d65565b901c614d8b565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614ceb83838585614e22565b9098509050614cfc88828e88614e46565b9098509050614d0d88828c87614e46565b90985090506000614d208d878b85614e46565b9098509050614d3188828686614e22565b9098509050614d4288828e89614e46565b9098509050818114614d77576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614d7b565b8196505b5050505050509450945094915050565b600080614d96614f30565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614dc8614f4e565b60208160c0846005600019fa925082614e185760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b60448201526064016108db565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614ee4579160200282015b82811115614ee457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614eaf565b50614ef0929150614f6c565b5090565b50805460008255906000526020600020908101906123c59190614f6c565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614ef05760008155600101614f6d565b8035611f7581615f53565b600082601f830112614f9d57600080fd5b813560206001600160401b03821115614fb857614fb8615f3d565b8160051b614fc7828201615d0b565b838152828101908684018388018501891015614fe257600080fd5b600093505b8584101561500e578035614ffa81615f53565b835260019390930192918401918401614fe7565b50979650505050505050565b600082601f83011261502b57600080fd5b615033615c9e565b80838560408601111561504557600080fd5b60005b6002811015615067578135845260209384019390910190600101615048565b509095945050505050565b60008083601f84011261508457600080fd5b5081356001600160401b0381111561509b57600080fd5b6020830191508360208285010111156150b357600080fd5b9250929050565b600082601f8301126150cb57600080fd5b81356001600160401b038111156150e4576150e4615f3d565b6150f7601f8201601f1916602001615d0b565b81815284602083860101111561510c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561513b57600080fd5b615143615cc6565b905081356001600160401b03808216821461515d57600080fd5b81835260208401356020840152615176604085016151dc565b6040840152615187606085016151dc565b606084015261519860808501614f81565b608084015260a08401359150808211156151b157600080fd5b506151be848285016150ba565b60a08301525092915050565b803561ffff81168114611f7557600080fd5b803563ffffffff81168114611f7557600080fd5b80516001600160501b0381168114611f7557600080fd5b80356001600160601b0381168114611f7557600080fd5b60006020828403121561523057600080fd5b81356137b381615f53565b6000806040838503121561524e57600080fd5b823561525981615f53565b915061526760208401615207565b90509250929050565b6000806040838503121561528357600080fd5b823561528e81615f53565b9150602083013561529e81615f53565b809150509250929050565b600080606083850312156152bc57600080fd5b82356152c781615f53565b9150606083018410156152d957600080fd5b50926020919091019150565b600080600080606085870312156152fb57600080fd5b843561530681615f53565b93506020850135925060408501356001600160401b0381111561532857600080fd5b61533487828801615072565b95989497509550505050565b60006040828403121561535257600080fd5b6137b3838361501a565b60006020828403121561536e57600080fd5b81516137b381615f68565b60006020828403121561538b57600080fd5b5051919050565b600080602083850312156153a557600080fd5b82356001600160401b038111156153bb57600080fd5b6153c785828601615072565b90969095509350505050565b6000602082840312156153e557600080fd5b604051602081016001600160401b038111828210171561540757615407615f3d565b604052823561541581615f68565b81529392505050565b6000808284036101c081121561543357600080fd5b6101a08082121561544357600080fd5b61544b615ce8565b9150615457868661501a565b8252615466866040870161501a565b60208301526080850135604083015260a0850135606083015260c0850135608083015261549560e08601614f81565b60a08301526101006154a98782880161501a565b60c08401526154bc87610140880161501a565b60e0840152610180860135908301529092508301356001600160401b038111156154e557600080fd5b6154f185828601615129565b9150509250929050565b60006020828403121561550d57600080fd5b81356001600160401b0381111561552357600080fd5b820160c081850312156137b357600080fd5b60006020828403121561554757600080fd5b81356001600160401b038082111561555e57600080fd5b9083019060c0828603121561557257600080fd5b61557a615cc6565b823560ff8116811461558b57600080fd5b8152602083810135908201526155a360408401614f81565b60408201526060830135828111156155ba57600080fd5b6155c687828601614f8c565b6060830152506155d860808401615207565b60808201526155e960a08401615207565b60a082015295945050505050565b60006020828403121561560957600080fd5b6137b3826151ca565b60008060008060008086880360e081121561562c57600080fd5b615635886151ca565b9650615643602089016151dc565b9550615651604089016151dc565b945061565f606089016151dc565b9350608088013592506040609f198201121561567a57600080fd5b50615683615c9e565b61568f60a089016151dc565b815261569d60c089016151dc565b6020820152809150509295509295509295565b6000602082840312156156c257600080fd5b5035919050565b600080604083850312156156dc57600080fd5b82359150602083013561529e81615f53565b6000806040838503121561570157600080fd5b50508035926020909101359150565b60006020828403121561572257600080fd5b6137b3826151dc565b600080600080600060a0868803121561574357600080fd5b61574c866151f0565b945060208601519350604086015192506060860151915061576f608087016151f0565b90509295509295909350565b600081518084526020808501945080840160005b838110156157b45781516001600160a01b03168752958201959082019060010161578f565b509495945050505050565b8060005b60028110156109405781518452602093840193909101906001016157c3565b600081518084526020808501945080840160005b838110156157b4578151875295820195908201906001016157f6565b6000815180845261582a816020860160208601615e63565b601f01601f19169290920160200192915050565b61584881836157bf565b604001919050565b60008351615862818460208801615e63565b835190830190615876818360208801615e63565b01949350505050565b86815261588f60208201876157bf565b61589c60608201866157bf565b6158a960a08201856157bf565b6158b660e08201846157bf565b60609190911b6001600160601b0319166101208201526101340195945050505050565b8381526158e960208201846157bf565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b60408101610f9882846157bf565b6020815260006137b360208301846157e2565b918252602082015260400190565b93845260ff9290921660208401526040830152606082015260800190565b6020815260006137b36020830184615812565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c06080840152615a0860e084018261577b565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b61ffff93841681529183166020830152909116604082015260600190565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615aa757845183529383019391830191600101615a8b565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016137b360208301846157bf565b82815260406020820152600061380160408301846157e2565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613fc160c0830184615812565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906140e590830184615812565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906140e590830184615812565b63ffffffff92831681529116602082015260400190565b6001600160401b0391909116815260200190565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615c4d9083018461577b565b979650505050505050565b6000808335601e19843603018112615c6f57600080fd5b8301803591506001600160401b03821115615c8957600080fd5b6020019150368190038213156150b357600080fd5b604080519081016001600160401b0381118282101715615cc057615cc0615f3d565b60405290565b60405160c081016001600160401b0381118282101715615cc057615cc0615f3d565b60405161012081016001600160401b0381118282101715615cc057615cc0615f3d565b604051601f8201601f191681016001600160401b0381118282101715615d3357615d33615f3d565b604052919050565b60008085851115615d4b57600080fd5b83861115615d5857600080fd5b5050820193919092039150565b60008219821115615d7857615d78615ee5565b500190565b60006001600160401b0382811684821680830382111561587657615876615ee5565b60006001600160601b0382811684821680830382111561587657615876615ee5565b600082615dd057615dd0615efb565b500490565b6000816000190483118215151615615def57615def615ee5565b500290565b600082821015615e0657615e06615ee5565b500390565b60006001600160601b0383811690831681811015615e2b57615e2b615ee5565b039392505050565b6001600160e01b03198135818116916004851015615e5b5780818660040360031b1b83161692505b505092915050565b60005b83811015615e7e578181015183820152602001615e66565b838111156109405750506000910152565b6000600019821415615ea357615ea3615ee5565b5060010190565b60006001600160401b0382811680821415615ec757615ec7615ee5565b6001019392505050565b600082615ee057615ee0615efb565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146123c557600080fd5b80151581146123c557600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var VRFCoordinatorV2PlusUpgradedVersionABI = VRFCoordinatorV2PlusUpgradedVersionMetaData.ABI @@ -560,58 +560,6 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionC return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SCurrentSubNonce(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_fallbackWeiPerUnitLink") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) SFallbackWeiPerUnitLink() (*big.Int, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFallbackWeiPerUnitLink(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCallerSession) SFallbackWeiPerUnitLink() (*big.Int, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFallbackWeiPerUnitLink(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SFeeConfig(opts *bind.CallOpts) (SFeeConfig, - - error) { - var out []interface{} - err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_feeConfig") - - outstruct := new(SFeeConfig) - if err != nil { - return *outstruct, err - } - - outstruct.FulfillmentFlatFeeLinkPPM = *abi.ConvertType(out[0], new(uint32)).(*uint32) - outstruct.FulfillmentFlatFeeNativePPM = *abi.ConvertType(out[1], new(uint32)).(*uint32) - - return *outstruct, err - -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) SFeeConfig() (SFeeConfig, - - error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFeeConfig(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCallerSession) SFeeConfig() (SFeeConfig, - - error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SFeeConfig(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts) -} - func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SProvingKeyHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { var out []interface{} err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_provingKeyHashes", arg0) @@ -634,28 +582,6 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionC return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeyHashes(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (common.Address, error) { - var out []interface{} - err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_provingKeys", arg0) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) SProvingKeys(arg0 [32]byte) (common.Address, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeys(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCallerSession) SProvingKeys(arg0 [32]byte) (common.Address, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.SProvingKeys(&_VRFCoordinatorV2PlusUpgradedVersion.CallOpts, arg0) -} - func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionCaller) SRequestCommitments(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { var out []interface{} err := _VRFCoordinatorV2PlusUpgradedVersion.contract.Call(opts, &out, "s_requestCommitments", arg0) @@ -3331,10 +3257,6 @@ type SConfig struct { StalenessSeconds uint32 GasAfterPaymentCalculation uint32 } -type SFeeConfig struct { - FulfillmentFlatFeeLinkPPM uint32 - FulfillmentFlatFeeNativePPM uint32 -} func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersion) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { @@ -3491,16 +3413,8 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { SCurrentSubNonce(opts *bind.CallOpts) (uint64, error) - SFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) - - SFeeConfig(opts *bind.CallOpts) (SFeeConfig, - - error) - SProvingKeyHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) - SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (common.Address, error) - SRequestCommitments(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) STotalBalance(opts *bind.CallOpts) (*big.Int, error) diff --git a/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go b/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go index ad44910797d..2cb4edd2082 100644 --- a/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go +++ b/core/gethwrappers/generated/vrfv2_proxy_admin/vrfv2_proxy_admin.go @@ -31,8 +31,8 @@ var ( ) var VRFV2ProxyAdminMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contractTransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeProxyAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractTransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractTransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractTransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractTransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610a1f8061007e6000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461012b57806399a88ec41461013e578063f2fde38b1461015e578063f3b7dead1461017e57600080fd5b8063204e1c7a14610080578063715018a6146100c95780637eff275e146100e05780638da5cb5b14610100575b600080fd5b34801561008c57600080fd5b506100a061009b3660046107c2565b61019e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d557600080fd5b506100de610255565b005b3480156100ec57600080fd5b506100de6100fb366004610803565b6102e7565b34801561010c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100a0565b6100de61013936600461083c565b6103ee565b34801561014a57600080fd5b506100de610159366004610803565b6104fc565b34801561016a57600080fd5b506100de6101793660046107c2565b6105d1565b34801561018a57600080fd5b506100a06101993660046107c2565b610701565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b600060405180830381855afa9150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b50915091508161023957600080fd5b8080602001905181019061024d91906107e6565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6102e5600061074d565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610368576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102d2565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b600060405180830381600087803b1580156103d257600080fd5b505af11580156103e6573d6000803e3d6000fd5b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102d2565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef2869034906104c59086908690600401610930565b6000604051808303818588803b1580156104de57600080fd5b505af11580156104f2573d6000803e3d6000fd5b5050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461057d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102d2565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016103b8565b60005473ffffffffffffffffffffffffffffffffffffffff163314610652576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102d2565b73ffffffffffffffffffffffffffffffffffffffff81166106f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102d2565b6106fe8161074d565b50565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156107d457600080fd5b81356107df816109f0565b9392505050565b6000602082840312156107f857600080fd5b81516107df816109f0565b6000806040838503121561081657600080fd5b8235610821816109f0565b91506020830135610831816109f0565b809150509250929050565b60008060006060848603121561085157600080fd5b833561085c816109f0565b9250602084013561086c816109f0565b9150604084013567ffffffffffffffff8082111561088957600080fd5b818601915086601f83011261089d57600080fd5b8135818111156108af576108af6109c1565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156108f5576108f56109c1565b8160405282815289602084870101111561090e57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8316815260006020604081840152835180604085015260005b8181101561097a5785810183015185820160600152820161095e565b8181111561098c576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146106fe57600080fdfea164736f6c6343000806000a", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contractITransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeProxyAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractITransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractITransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractITransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractITransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6108438061007e6000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461012b57806399a88ec41461013e578063f2fde38b1461015e578063f3b7dead1461017e57600080fd5b8063204e1c7a14610080578063715018a6146100c95780637eff275e146100e05780638da5cb5b14610100575b600080fd5b34801561008c57600080fd5b506100a061009b3660046105e6565b61019e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100d557600080fd5b506100de610255565b005b3480156100ec57600080fd5b506100de6100fb366004610627565b610269565b34801561010c57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166100a0565b6100de610139366004610660565b6102f7565b34801561014a57600080fd5b506100de610159366004610627565b61038c565b34801561016a57600080fd5b506100de6101793660046105e6565b6103e8565b34801561018a57600080fd5b506100a06101993660046105e6565b6104a4565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907f5c60da1b00000000000000000000000000000000000000000000000000000000815260040190565b600060405180830381855afa9150503d8060008114610225576040519150601f19603f3d011682016040523d82523d6000602084013e61022a565b606091505b50915091508161023957600080fd5b8080602001905181019061024d919061060a565b949350505050565b61025d6104f0565b6102676000610571565b565b6102716104f0565b6040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690638f283970906024015b600060405180830381600087803b1580156102db57600080fd5b505af11580156102ef573d6000803e3d6000fd5b505050505050565b6102ff6104f0565b6040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690634f1ef2869034906103559086908690600401610754565b6000604051808303818588803b15801561036e57600080fd5b505af1158015610382573d6000803e3d6000fd5b5050505050505050565b6103946104f0565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8281166004830152831690633659cfe6906024016102c1565b6103f06104f0565b73ffffffffffffffffffffffffffffffffffffffff8116610498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6104a181610571565b50565b60008060008373ffffffffffffffffffffffffffffffffffffffff166040516101ea907ff851a44000000000000000000000000000000000000000000000000000000000815260040190565b60005473ffffffffffffffffffffffffffffffffffffffff163314610267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161048f565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156105f857600080fd5b813561060381610814565b9392505050565b60006020828403121561061c57600080fd5b815161060381610814565b6000806040838503121561063a57600080fd5b823561064581610814565b9150602083013561065581610814565b809150509250929050565b60008060006060848603121561067557600080fd5b833561068081610814565b9250602084013561069081610814565b9150604084013567ffffffffffffffff808211156106ad57600080fd5b818601915086601f8301126106c157600080fd5b8135818111156106d3576106d36107e5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610719576107196107e5565b8160405282815289602084870101111561073257600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b73ffffffffffffffffffffffffffffffffffffffff8316815260006020604081840152835180604085015260005b8181101561079e57858101830151858201606001528201610782565b818111156107b0576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146104a157600080fdfea164736f6c6343000806000a", } var VRFV2ProxyAdminABI = VRFV2ProxyAdminMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go b/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go index f055b211da4..657cc1894f3 100644 --- a/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go +++ b/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy/vrfv2_transparent_upgradeable_proxy.go @@ -31,8 +31,8 @@ var ( ) var VRFV2TransparentUpgradeableProxyMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"implementation_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x60806040526040516200113b3803806200113b8339810160408190526200002691620004c8565b82828282816200005860017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005fb565b600080516020620010f48339815191521462000078576200007862000650565b6200008682826000620000ed565b50620000b6905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005fb565b600080516020620010d483398151915214620000d657620000d662000650565b620000e1826200012a565b5050505050506200067c565b620000f88362000185565b600082511180620001065750805b156200012557620001238383620001c760201b620002ff1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f62000155620001f6565b604080516001600160a01b03928316815291841660208301520160405180910390a162000182816200022f565b50565b6200019081620002e4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001ef8383604051806060016040528060278152602001620011146027913962000387565b9392505050565b600062000220600080516020620010d483398151915260001b6200046460201b620002731760201c565b546001600160a01b0316919050565b6001600160a01b0381166200029a5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002c3600080516020620010d483398151915260001b6200046460201b620002731760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002fa816200046760201b6200032b1760201c565b6200035e5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000291565b80620002c3600080516020620010f483398151915260001b6200046460201b620002731760201c565b6060833b620003e85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840162000291565b600080856001600160a01b031685604051620004059190620005a8565b600060405180830381855af49150503d806000811462000442576040519150601f19603f3d011682016040523d82523d6000602084013e62000447565b606091505b5090925090506200045a8282866200046d565b9695505050505050565b90565b3b151590565b606083156200047e575081620001ef565b8251156200048f5782518084602001fd5b8160405162461bcd60e51b8152600401620002919190620005c6565b80516001600160a01b0381168114620004c357600080fd5b919050565b600080600060608486031215620004de57600080fd5b620004e984620004ab565b9250620004f960208501620004ab565b60408501519092506001600160401b03808211156200051757600080fd5b818601915086601f8301126200052c57600080fd5b81518181111562000541576200054162000666565b604051601f8201601f19908116603f011681019083821181831017156200056c576200056c62000666565b816040528281528960208487010111156200058657600080fd5b6200059983602083016020880162000621565b80955050505050509250925092565b60008251620005bc81846020870162000621565b9190910192915050565b6020815260008251806020840152620005e781604085016020870162000621565b601f01601f19169190910160400192915050565b6000828210156200061c57634e487b7160e01b600052601160045260246000fd5b500390565b60005b838110156200063e57818101518382015260200162000624565b83811115620001235750506000910152565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b610a48806200068c6000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b6100903660046108dd565b610135565b61006b6100a33660046108f8565b610196565b3480156100b457600080fd5b506100bd610221565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b6101013660046108dd565b610276565b34801561011257600080fd5b506100bd6102ba565b610123610331565b61013361012e61041f565b610429565b565b61013d61044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b8160405180602001604052806000815250600061048d565b50565b61018b61011b565b61019e61044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610219576102148383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061048d915050565b505050565b61021461011b565b600061022b61044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b5761026661041f565b905090565b61027361011b565b90565b61027e61044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816104b8565b60006102c461044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b5761026661044d565b60606103248383604051806060016040528060278152602001610a1560279139610519565b9392505050565b3b151590565b61033961044d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b600061026661062b565b3660008037600080366000845af43d6000803e808015610448573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b61049683610653565b6000825111806104a35750805b15610214576104b283836102ff565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104e161044d565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161018b816106a0565b6060833b6105a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e747261637400000000000000000000000000000000000000000000000000006064820152608401610416565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105d1919061097b565b600060405180830381855af49150503d806000811461060c576040519150601f19603f3d011682016040523d82523d6000602084013e610611565b606091505b50915091506106218282866107ac565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610471565b61065c816107ff565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff8116610743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610416565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b606083156107bb575081610324565b8251156107cb5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104169190610997565b803b61088d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610416565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610766565b803573ffffffffffffffffffffffffffffffffffffffff811681146108d857600080fd5b919050565b6000602082840312156108ef57600080fd5b610324826108b4565b60008060006040848603121561090d57600080fd5b610916846108b4565b9250602084013567ffffffffffffffff8082111561093357600080fd5b818601915086601f83011261094757600080fd5b81358181111561095657600080fd5b87602082850101111561096857600080fd5b6020830194508093505050509250925092565b6000825161098d8184602087016109e8565b9190910192915050565b60208152600082518060208401526109b68160408501602087016109e8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60005b83811015610a035781810151838201526020016109eb565b838111156104b2575050600091015256fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000806000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x6080604052604051620011863803806200118683398101604081905262000026916200045e565b8282828281620000398282600062000053565b506200004790508262000090565b505050505050620005d6565b6200005e83620000eb565b6000825111806200006c5750805b156200008b576200008983836200012d60201b620002bd1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000bb6200015c565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000e88162000195565b50565b620000f6816200024a565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200015583836040518060600160405280602781526020016200115f60279139620002fe565b9392505050565b6000620001866000805160206200113f83398151915260001b6200037d60201b620002e91760201c565b546001600160a01b0316919050565b6001600160a01b038116620002005760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002296000805160206200113f83398151915260001b6200037d60201b620002e91760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b62000260816200038060201b620002ec1760201c565b620002c45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001f7565b80620002297f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b6200037d60201b620002e91760201c565b6060600080856001600160a01b0316856040516200031d91906200053e565b600060405180830381855af49150503d80600081146200035a576040519150601f19603f3d011682016040523d82523d6000602084013e6200035f565b606091505b50909250905062000373868383876200038f565b9695505050505050565b90565b6001600160a01b03163b151590565b6060831562000400578251620003f8576001600160a01b0385163b620003f85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001f7565b50816200040c565b6200040c838362000414565b949350505050565b815115620004255781518083602001fd5b8060405162461bcd60e51b8152600401620001f791906200055c565b80516001600160a01b03811681146200045957600080fd5b919050565b6000806000606084860312156200047457600080fd5b6200047f8462000441565b92506200048f6020850162000441565b60408501519092506001600160401b0380821115620004ad57600080fd5b818601915086601f830112620004c257600080fd5b815181811115620004d757620004d7620005c0565b604051601f8201601f19908116603f01168101908382118183101715620005025762000502620005c0565b816040528281528960208487010111156200051c57600080fd5b6200052f83602083016020880162000591565b80955050505050509250925092565b600082516200055281846020870162000591565b9190910192915050565b60208152600082518060208401526200057d81604085016020870162000591565b601f01601f19169190910160400192915050565b60005b83811015620005ae57818101518382015260200162000594565b83811115620000895750506000910152565b634e487b7160e01b600052604160045260246000fd5b610b5980620005e66000396000f3fe60806040523661001357610011610017565b005b6100115b61001f610308565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102b35760607fffffffff00000000000000000000000000000000000000000000000000000000600035167f3659cfe6000000000000000000000000000000000000000000000000000000008114156100b0576100a9610348565b91506102ab565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f4f1ef286000000000000000000000000000000000000000000000000000000001415610102576100a961039f565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f8f283970000000000000000000000000000000000000000000000000000000001415610154576100a96103e5565b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff851a4400000000000000000000000000000000000000000000000000000000014156101a6576100a9610416565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f5c60da1b0000000000000000000000000000000000000000000000000000000014156101f8576100a9610463565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b815160208301f35b6102bb610477565b565b60606102e28383604051806060016040528060278152602001610b2660279139610487565b9392505050565b90565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b606061035261050c565b60006103613660048184610aa0565b81019061036e9190610938565b905061038b81604051806020016040528060008152506000610517565b505060408051602081019091526000815290565b60606000806103b13660048184610aa0565b8101906103be9190610953565b915091506103ce82826001610517565b604051806020016040528060008152509250505090565b60606103ef61050c565b60006103fe3660048184610aa0565b81019061040b9190610938565b905061038b81610543565b606061042061050c565b600061042a610308565b6040805173ffffffffffffffffffffffffffffffffffffffff831660208201529192500160405160208183030381529060405291505090565b606061046d61050c565b600061042a6105a7565b6102bb6104826105a7565b6105b6565b60606000808573ffffffffffffffffffffffffffffffffffffffff16856040516104b19190610a33565b600060405180830381855af49150503d80600081146104ec576040519150601f19603f3d011682016040523d82523d6000602084013e6104f1565b606091505b5091509150610502868383876105da565b9695505050505050565b34156102bb57600080fd5b6105208361067f565b60008251118061052d5750805b1561053e5761053c83836102bd565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61056c610308565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a16105a4816106cc565b50565b60006105b16107d8565b905090565b3660008037600080366000845af43d6000803e8080156105d5573d6000f35b3d6000fd5b6060831561066d5782516106665773ffffffffffffffffffffffffffffffffffffffff85163b610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102a2565b5081610677565b6106778383610800565b949350505050565b61068881610844565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff811661076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102a2565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61032c565b8151156108105781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a29190610a4f565b73ffffffffffffffffffffffffffffffffffffffff81163b6108e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016102a2565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610792565b803573ffffffffffffffffffffffffffffffffffffffff8116811461093357600080fd5b919050565b60006020828403121561094a57600080fd5b6102e28261090f565b6000806040838503121561096657600080fd5b61096f8361090f565b9150602083013567ffffffffffffffff8082111561098c57600080fd5b818501915085601f8301126109a057600080fd5b8135818111156109b2576109b2610af6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109f8576109f8610af6565b81604052828152886020848701011115610a1157600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008251610a45818460208701610aca565b9190910192915050565b6020815260008251806020840152610a6e816040850160208701610aca565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008085851115610ab057600080fd5b83861115610abd57600080fd5b5050820193919092039150565b60005b83811015610ae5578181015183820152602001610acd565b8381111561053c5750506000910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a164736f6c6343000806000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", } var VRFV2TransparentUpgradeableProxyABI = VRFV2TransparentUpgradeableProxyMetaData.ABI @@ -171,66 +171,6 @@ func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransac return _VRFV2TransparentUpgradeableProxy.Contract.contract.Transact(opts, method, params...) } -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) Admin(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.contract.Transact(opts, "admin") -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxySession) Admin() (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.Admin(&_VRFV2TransparentUpgradeableProxy.TransactOpts) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactorSession) Admin() (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.Admin(&_VRFV2TransparentUpgradeableProxy.TransactOpts) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) ChangeAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.contract.Transact(opts, "changeAdmin", newAdmin) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxySession) ChangeAdmin(newAdmin common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.ChangeAdmin(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newAdmin) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactorSession) ChangeAdmin(newAdmin common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.ChangeAdmin(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newAdmin) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) Implementation(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.contract.Transact(opts, "implementation") -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxySession) Implementation() (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.Implementation(&_VRFV2TransparentUpgradeableProxy.TransactOpts) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactorSession) Implementation() (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.Implementation(&_VRFV2TransparentUpgradeableProxy.TransactOpts) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) UpgradeTo(opts *bind.TransactOpts, newImplementation common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.contract.Transact(opts, "upgradeTo", newImplementation) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxySession) UpgradeTo(newImplementation common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.UpgradeTo(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newImplementation) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactorSession) UpgradeTo(newImplementation common.Address) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.UpgradeTo(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newImplementation) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) UpgradeToAndCall(opts *bind.TransactOpts, newImplementation common.Address, data []byte) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.contract.Transact(opts, "upgradeToAndCall", newImplementation, data) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxySession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.UpgradeToAndCall(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newImplementation, data) -} - -func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactorSession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { - return _VRFV2TransparentUpgradeableProxy.Contract.UpgradeToAndCall(&_VRFV2TransparentUpgradeableProxy.TransactOpts, newImplementation, data) -} - func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxyTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { return _VRFV2TransparentUpgradeableProxy.contract.RawTransact(opts, calldata) } @@ -658,16 +598,6 @@ func (_VRFV2TransparentUpgradeableProxy *VRFV2TransparentUpgradeableProxy) Addre } type VRFV2TransparentUpgradeableProxyInterface interface { - Admin(opts *bind.TransactOpts) (*types.Transaction, error) - - ChangeAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) - - Implementation(opts *bind.TransactOpts) (*types.Transaction, error) - - UpgradeTo(opts *bind.TransactOpts, newImplementation common.Address) (*types.Transaction, error) - - UpgradeToAndCall(opts *bind.TransactOpts, newImplementation common.Address, data []byte) (*types.Transaction, error) - Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) Receive(opts *bind.TransactOpts) (*types.Transaction, error) diff --git a/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go b/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go index e50c335e03b..61cb52e117d 100644 --- a/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go +++ b/core/gethwrappers/generated/vrfv2_wrapper/vrfv2_wrapper.go @@ -32,7 +32,7 @@ var ( var VRFV2WrapperMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkEthFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractExtendedVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINK_ETH_FEED\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"requestGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"int256\",\"name\":\"requestWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"juelsPaid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"_wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101206040526001805463ffffffff60a01b1916609160a21b1790553480156200002857600080fd5b50604051620025d0380380620025d08339810160408190526200004b91620002d8565b803380600081620000a35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d657620000d6816200020f565b5050506001600160601b0319606091821b811660805284821b811660a05283821b811660c0529082901b1660e0526040805163288688f960e21b815290516000916001600160a01b0384169163a21a23e49160048082019260209290919082900301818787803b1580156200014a57600080fd5b505af11580156200015f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000185919062000322565b60c081901b6001600160c01b03191661010052604051631cd0704360e21b81526001600160401b03821660048201523060248201529091506001600160a01b03831690637341c10c90604401600060405180830381600087803b158015620001ec57600080fd5b505af115801562000201573d6000803e3d6000fd5b505050505050505062000354565b6001600160a01b0381163314156200026a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009a565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620002d357600080fd5b919050565b600080600060608486031215620002ee57600080fd5b620002f984620002bb565b92506200030960208501620002bb565b91506200031960408501620002bb565b90509250925092565b6000602082840312156200033557600080fd5b81516001600160401b03811681146200034d57600080fd5b9392505050565b60805160601c60a05160601c60c05160601c60e05160601c6101005160c01c6121e9620003e7600039600081816101970152610c5501526000818161028401528181610c1601528181610fec015281816110cd01526111680152600081816103fd015261161c01526000818161021b01528181610a6801526112ba01526000818161055801526105c001526121e96000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80638da5cb5b116100e3578063c15ce4d71161008c578063f2fde38b11610066578063f2fde38b14610511578063f3fef3a314610524578063fc2a88c31461053757600080fd5b8063c15ce4d714610432578063c3f909d414610445578063cdd8d885146104d457600080fd5b8063a608a1e1116100bd578063a608a1e1146103e6578063ad178361146103f8578063bf17e5591461041f57600080fd5b80638da5cb5b146103ad578063a3907d71146103cb578063a4c0ed36146103d357600080fd5b80633b2bcbf11161014557806357a8070a1161011f57806357a8070a1461037557806379ba5097146103925780637fb5d19d1461039a57600080fd5b80633b2bcbf11461027f5780634306d354146102a657806348baa1c5146102c757600080fd5b80631b6b6d23116101765780631b6b6d23146102165780631fe543e3146102625780632f2770db1461027757600080fd5b8063030932bb14610192578063181f5a77146101d7575b600080fd5b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b604080518082018252601281527f56524656325772617070657220312e302e300000000000000000000000000000602082015290516101ce9190611f7c565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ce565b610275610270366004611c61565b610540565b005b610275610600565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b6102b96102b4366004611d9a565b610636565b6040519081526020016101ce565b6103316102d5366004611c48565b600860205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff8316937401000000000000000000000000000000000000000090930463ffffffff16929085565b6040805173ffffffffffffffffffffffffffffffffffffffff909616865263ffffffff9094166020860152928401919091526060830152608082015260a0016101ce565b6003546103829060ff1681565b60405190151581526020016101ce565b61027561073d565b6102b96103a8366004611e02565b61083a565b60005473ffffffffffffffffffffffffffffffffffffffff1661023d565b610275610940565b6102756103e1366004611b27565b610972565b60035461038290610100900460ff1681565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b61027561042d366004611d9a565b610e50565b610275610440366004611ed6565b610ea7565b6004546005546006546007546040805194855263ffffffff80851660208701526401000000008504811691860191909152680100000000000000008404811660608601526c01000000000000000000000000840416608085015260ff700100000000000000000000000000000000909304831660a085015260c08401919091521660e0820152610100016101ce565b6001546104fc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101ce565b61027561051f366004611ae2565b611252565b610275610532366004611afd565b611266565b6102b960025481565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105f2576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6105fc828261133b565b5050565b610608611546565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b60035460009060ff166106a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff1615610717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b60006107216115c9565b90506107348363ffffffff163a8361173d565b9150505b919050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105e9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60035460009060ff166108a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff161561091b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b60006109256115c9565b90506109388463ffffffff16848361173d565b949350505050565b610948611546565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60035460ff166109de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff1615610a50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610aef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b00000000000000000060448201526064016105e9565b60008080610aff84860186611db7565b9250925092506000610b108461185e565b90506000610b1c6115c9565b90506000610b318663ffffffff163a8461173d565b905080891015610b9d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f7700000000000000000000000000000000000000000060448201526064016105e9565b60075460ff1663ffffffff85161115610c12576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f206869676800000000000000000000000000000060448201526064016105e9565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635d3b1d306006547f000000000000000000000000000000000000000000000000000000000000000089600560089054906101000a900463ffffffff16898d610c949190612055565b610c9e9190612055565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152600481019490945267ffffffffffffffff909216602484015261ffff16604483015263ffffffff90811660648301528816608482015260a401602060405180830381600087803b158015610d1d57600080fd5b505af1158015610d31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d559190611bd0565b90506040518060a001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018863ffffffff1681526020013a81526020018481526020018b8152506008600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff160217905550604082015181600101556060820151816002015560808201518160030155905050806002819055505050505050505050505050565b610e58611546565b6001805463ffffffff90921674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b610eaf611546565b6005805460ff808616700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff63ffffffff8981166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff918c166801000000000000000002919091167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff909516949094179390931792909216919091179091556006839055600780549183167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00928316179055600380549091166001179055604080517fc3f909d4000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163c3f909d4916004828101926080929190829003018186803b15801561103257600080fd5b505afa158015611046573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106a9190611be9565b50600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555050604080517f356dac7100000000000000000000000000000000000000000000000000000000815290517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169163356dac71916004808301926020929190829003018186803b15801561112857600080fd5b505afa15801561113c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111609190611bd0565b6004819055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635fbbc0d26040518163ffffffff1660e01b81526004016101206040518083038186803b1580156111cd57600080fd5b505afa1580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112059190611e20565b50506005805463ffffffff909816640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff909816979097179096555050505050505050505050565b61125a611546565b6112638161187c565b50565b61126e611546565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b1580156112fe57600080fd5b505af1158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190611bae565b505050565b6000828152600860208181526040808420815160a081018352815473ffffffffffffffffffffffffffffffffffffffff808216835263ffffffff740100000000000000000000000000000000000000008304168387015260018401805495840195909552600284018054606085015260038501805460808601528b8a52979096527fffffffffffffffff000000000000000000000000000000000000000000000000909116909255918590559184905592909155815116611458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e6400000000000000000000000000000060448201526064016105e9565b600080631fe543e360e01b8585604051602401611476929190611fef565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006114f0846020015163ffffffff16856000015184611972565b90508061153e57835160405173ffffffffffffffffffffffffffffffffffffffff9091169087907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115c7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105e9565b565b600554604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009263ffffffff161515918391829173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163feaf968c9160048082019260a092909190829003018186803b15801561166357600080fd5b505afa158015611677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169b9190611f38565b5094509092508491505080156116c157506116b68242612116565b60055463ffffffff16105b156116cb57506004545b6000811215611736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b207765692070726963650000000000000000000060448201526064016105e9565b9392505050565b600154600090819061176c9074010000000000000000000000000000000000000000900463ffffffff166119be565b60055463ffffffff6c01000000000000000000000000820481169161179f9168010000000000000000909104168861203d565b6117a9919061203d565b6117b390866120d9565b6117bd919061203d565b90506000836117d483670de0b6b3a76400006120d9565b6117de91906120a2565b60055490915060009060649061180b90700100000000000000000000000000000000900460ff168261207d565b6118189060ff16846120d9565b61182291906120a2565b60055490915060009061184890640100000000900463ffffffff1664e8d4a510006120d9565b611852908361203d565b98975050505050505050565b600061186b603f836120b6565b611876906001612055565b92915050565b73ffffffffffffffffffffffffffffffffffffffff81163314156118fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105e9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a61138881101561198457600080fd5b61138881039050846040820482031161199c57600080fd5b50823b6119a857600080fd5b60008083516020850160008789f1949350505050565b60004661a4b18114806119d3575062066eed81145b15611a77576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b158015611a2157600080fd5b505afa158015611a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a599190611d50565b5050505091505083608c611a6d919061203d565b61093890826120d9565b50600092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461073857600080fd5b805162ffffff8116811461073857600080fd5b803560ff8116811461073857600080fd5b805169ffffffffffffffffffff8116811461073857600080fd5b600060208284031215611af457600080fd5b61173682611a80565b60008060408385031215611b1057600080fd5b611b1983611a80565b946020939093013593505050565b60008060008060608587031215611b3d57600080fd5b611b4685611a80565b935060208501359250604085013567ffffffffffffffff80821115611b6a57600080fd5b818701915087601f830112611b7e57600080fd5b813581811115611b8d57600080fd5b886020828501011115611b9f57600080fd5b95989497505060200194505050565b600060208284031215611bc057600080fd5b8151801515811461173657600080fd5b600060208284031215611be257600080fd5b5051919050565b60008060008060808587031215611bff57600080fd5b8451611c0a816121ba565b6020860151909450611c1b816121ca565b6040860151909350611c2c816121ca565b6060860151909250611c3d816121ca565b939692955090935050565b600060208284031215611c5a57600080fd5b5035919050565b60008060408385031215611c7457600080fd5b8235915060208084013567ffffffffffffffff80821115611c9457600080fd5b818601915086601f830112611ca857600080fd5b813581811115611cba57611cba61218b565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715611cfd57611cfd61218b565b604052828152858101935084860182860187018b1015611d1c57600080fd5b600095505b83861015611d3f578035855260019590950194938601938601611d21565b508096505050505050509250929050565b60008060008060008060c08789031215611d6957600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060208284031215611dac57600080fd5b8135611736816121ca565b600080600060608486031215611dcc57600080fd5b8335611dd7816121ca565b92506020840135611de7816121ba565b91506040840135611df7816121ca565b809150509250925092565b60008060408385031215611e1557600080fd5b8235611b19816121ca565b60008060008060008060008060006101208a8c031215611e3f57600080fd5b8951611e4a816121ca565b60208b0151909950611e5b816121ca565b60408b0151909850611e6c816121ca565b60608b0151909750611e7d816121ca565b60808b0151909650611e8e816121ca565b9450611e9c60a08b01611aa4565b9350611eaa60c08b01611aa4565b9250611eb860e08b01611aa4565b9150611ec76101008b01611aa4565b90509295985092959850929598565b600080600080600060a08688031215611eee57600080fd5b8535611ef9816121ca565b94506020860135611f09816121ca565b9350611f1760408701611ab7565b925060608601359150611f2c60808701611ab7565b90509295509295909350565b600080600080600060a08688031215611f5057600080fd5b611f5986611ac8565b9450602086015193506040860151925060608601519150611f2c60808701611ac8565b600060208083528351808285015260005b81811015611fa957858101830151858201604001528201611f8d565b81811115611fbb576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000604082018483526020604081850152818551808452606086019150828701935060005b8181101561203057845183529383019391830191600101612014565b5090979650505050505050565b600082198211156120505761205061212d565b500190565b600063ffffffff8083168185168083038211156120745761207461212d565b01949350505050565b600060ff821660ff84168060ff0382111561209a5761209a61212d565b019392505050565b6000826120b1576120b161215c565b500490565b600063ffffffff808416806120cd576120cd61215c565b92169190910492915050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156121115761211161212d565b500290565b6000828210156121285761212861212d565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61ffff8116811461126357600080fd5b63ffffffff8116811461126357600080fdfea164736f6c6343000806000a", + Bin: "0x6101206040526001805463ffffffff60a01b1916609160a21b1790553480156200002857600080fd5b5060405162002a3c38038062002a3c8339810160408190526200004b91620002d8565b803380600081620000a35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d657620000d6816200020f565b5050506001600160601b0319606091821b811660805284821b811660a05283821b811660c0529082901b1660e0526040805163288688f960e21b815290516000916001600160a01b0384169163a21a23e49160048082019260209290919082900301818787803b1580156200014a57600080fd5b505af11580156200015f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000185919062000322565b60c081901b6001600160c01b03191661010052604051631cd0704360e21b81526001600160401b03821660048201523060248201529091506001600160a01b03831690637341c10c90604401600060405180830381600087803b158015620001ec57600080fd5b505af115801562000201573d6000803e3d6000fd5b505050505050505062000354565b6001600160a01b0381163314156200026a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009a565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620002d357600080fd5b919050565b600080600060608486031215620002ee57600080fd5b620002f984620002bb565b92506200030960208501620002bb565b91506200031960408501620002bb565b90509250925092565b6000602082840312156200033557600080fd5b81516001600160401b03811681146200034d57600080fd5b9392505050565b60805160601c60a05160601c60c05160601c60e05160601c6101005160c01c612655620003e7600039600081816101970152610c5701526000818161028401528181610c1801528181610fee015281816110cf015261116a0152600081816103fd015261161e01526000818161021b01528181610a6a01526112bc01526000818161055801526105c001526126556000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80638da5cb5b116100e3578063c15ce4d71161008c578063f2fde38b11610066578063f2fde38b14610511578063f3fef3a314610524578063fc2a88c31461053757600080fd5b8063c15ce4d714610432578063c3f909d414610445578063cdd8d885146104d457600080fd5b8063a608a1e1116100bd578063a608a1e1146103e6578063ad178361146103f8578063bf17e5591461041f57600080fd5b80638da5cb5b146103ad578063a3907d71146103cb578063a4c0ed36146103d357600080fd5b80633b2bcbf11161014557806357a8070a1161011f57806357a8070a1461037557806379ba5097146103925780637fb5d19d1461039a57600080fd5b80633b2bcbf11461027f5780634306d354146102a657806348baa1c5146102c757600080fd5b80631b6b6d23116101765780631b6b6d23146102165780631fe543e3146102625780632f2770db1461027757600080fd5b8063030932bb14610192578063181f5a77146101d7575b600080fd5b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b604080518082018252601281527f56524656325772617070657220312e302e300000000000000000000000000000602082015290516101ce91906122c1565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ce565b610275610270366004611fa6565b610540565b005b610275610600565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b6102b96102b43660046120df565b610636565b6040519081526020016101ce565b6103316102d5366004611f8d565b600860205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff8316937401000000000000000000000000000000000000000090930463ffffffff16929085565b6040805173ffffffffffffffffffffffffffffffffffffffff909616865263ffffffff9094166020860152928401919091526060830152608082015260a0016101ce565b6003546103829060ff1681565b60405190151581526020016101ce565b61027561073d565b6102b96103a8366004612147565b61083a565b60005473ffffffffffffffffffffffffffffffffffffffff1661023d565b610275610942565b6102756103e1366004611e6c565b610974565b60035461038290610100900460ff1681565b61023d7f000000000000000000000000000000000000000000000000000000000000000081565b61027561042d3660046120df565b610e52565b61027561044036600461221b565b610ea9565b6004546005546006546007546040805194855263ffffffff80851660208701526401000000008504811691860191909152680100000000000000008404811660608601526c01000000000000000000000000840416608085015260ff700100000000000000000000000000000000909304831660a085015260c08401919091521660e0820152610100016101ce565b6001546104fc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101ce565b61027561051f366004611e27565b611254565b610275610532366004611e42565b611268565b6102b960025481565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105f2576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6105fc828261133d565b5050565b610608611548565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b60035460009060ff166106a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff1615610717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b60006107216115cb565b90506107348363ffffffff163a8361173f565b9150505b919050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105e9565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60035460009060ff166108a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff161561091b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b60006109256115cb565b90506109388463ffffffff16848361173f565b9150505b92915050565b61094a611548565b600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60035460ff166109e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e666967757265640000000000000060448201526064016105e9565b600354610100900460ff1615610a52576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c65640000000000000000000000000060448201526064016105e9565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b00000000000000000060448201526064016105e9565b60008080610b01848601866120fc565b9250925092506000610b1284611860565b90506000610b1e6115cb565b90506000610b338663ffffffff163a8461173f565b905080891015610b9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f7700000000000000000000000000000000000000000060448201526064016105e9565b60075460ff1663ffffffff85161115610c14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f206869676800000000000000000000000000000060448201526064016105e9565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635d3b1d306006547f000000000000000000000000000000000000000000000000000000000000000089600560089054906101000a900463ffffffff16898d610c96919061239a565b610ca0919061239a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152600481019490945267ffffffffffffffff909216602484015261ffff16604483015263ffffffff90811660648301528816608482015260a401602060405180830381600087803b158015610d1f57600080fd5b505af1158015610d33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d579190611f15565b90506040518060a001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018863ffffffff1681526020013a81526020018481526020018b8152506008600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff160217905550604082015181600101556060820151816002015560808201518160030155905050806002819055505050505050505050505050565b610e5a611548565b6001805463ffffffff90921674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b610eb1611548565b6005805460ff808616700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff63ffffffff8981166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff918c166801000000000000000002919091167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff909516949094179390931792909216919091179091556006839055600780549183167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00928316179055600380549091166001179055604080517fc3f909d4000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163c3f909d4916004828101926080929190829003018186803b15801561103457600080fd5b505afa158015611048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106c9190611f2e565b50600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555050604080517f356dac7100000000000000000000000000000000000000000000000000000000815290517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169163356dac71916004808301926020929190829003018186803b15801561112a57600080fd5b505afa15801561113e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111629190611f15565b6004819055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635fbbc0d26040518163ffffffff1660e01b81526004016101206040518083038186803b1580156111cf57600080fd5b505afa1580156111e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112079190612165565b50506005805463ffffffff909816640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff909816979097179096555050505050505050505050565b61125c611548565b61126581611878565b50565b611270611548565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b15801561130057600080fd5b505af1158015611314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113389190611ef3565b505050565b6000828152600860208181526040808420815160a081018352815473ffffffffffffffffffffffffffffffffffffffff808216835263ffffffff740100000000000000000000000000000000000000008304168387015260018401805495840195909552600284018054606085015260038501805460808601528b8a52979096527fffffffffffffffff00000000000000000000000000000000000000000000000090911690925591859055918490559290915581511661145a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e6400000000000000000000000000000060448201526064016105e9565b600080631fe543e360e01b8585604051602401611478929190612334565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060006114f2846020015163ffffffff1685600001518461196e565b90508061154057835160405173ffffffffffffffffffffffffffffffffffffffff9091169087907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105e9565b565b600554604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009263ffffffff161515918391829173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163feaf968c9160048082019260a092909190829003018186803b15801561166557600080fd5b505afa158015611679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169d919061227d565b5094509092508491505080156116c357506116b88242612582565b60055463ffffffff16105b156116cd57506004545b6000811215611738576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b207765692070726963650000000000000000000060448201526064016105e9565b9392505050565b600154600090819061176e9074010000000000000000000000000000000000000000900463ffffffff166119ba565b60055463ffffffff6c0100000000000000000000000082048116916117a191680100000000000000009091041688612382565b6117ab9190612382565b6117b59086612545565b6117bf9190612382565b90506000836117d683670de0b6b3a7640000612545565b6117e091906123e7565b60055490915060009060649061180d90700100000000000000000000000000000000900460ff16826123c2565b61181a9060ff1684612545565b61182491906123e7565b60055490915060009061184a90640100000000900463ffffffff1664e8d4a51000612545565b6118549083612382565b98975050505050505050565b600061186d603f836123fb565b61093c90600161239a565b73ffffffffffffffffffffffffffffffffffffffff81163314156118f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105e9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a61138881101561198057600080fd5b61138881039050846040820482031161199857600080fd5b50823b6119a457600080fd5b60008083516020850160008789f1949350505050565b6000466119c681611a92565b15611a72576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b158015611a1457600080fd5b505afa158015611a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c9190612095565b5050505091505083608c611a609190612382565b611a6a9082612545565b949350505050565b611a7b81611ab5565b15611a895761073483611aef565b50600092915050565b600061a4b1821480611aa6575062066eed82145b8061093c57505062066eee1490565b6000600a821480611ac757506101a482145b80611ad4575062aa37dc82145b80611ae0575061210582145b8061093c57505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b815260040160206040518083038186803b158015611b4c57600080fd5b505afa158015611b60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b849190611f15565b9050600080611b938186612582565b90506000611ba2826010612545565b611bad846004612545565b611bb79190612382565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b815260040160206040518083038186803b158015611c1557600080fd5b505afa158015611c29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4d9190611f15565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b505afa158015611cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce39190611f15565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015611d4157600080fd5b505afa158015611d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d799190611f15565b90506000611d8882600a61247f565b905060008184611d988789612382565b611da2908c612545565b611dac9190612545565b611db691906123e7565b9b9a5050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461073857600080fd5b805162ffffff8116811461073857600080fd5b803560ff8116811461073857600080fd5b805169ffffffffffffffffffff8116811461073857600080fd5b600060208284031215611e3957600080fd5b61173882611dc5565b60008060408385031215611e5557600080fd5b611e5e83611dc5565b946020939093013593505050565b60008060008060608587031215611e8257600080fd5b611e8b85611dc5565b935060208501359250604085013567ffffffffffffffff80821115611eaf57600080fd5b818701915087601f830112611ec357600080fd5b813581811115611ed257600080fd5b886020828501011115611ee457600080fd5b95989497505060200194505050565b600060208284031215611f0557600080fd5b8151801515811461173857600080fd5b600060208284031215611f2757600080fd5b5051919050565b60008060008060808587031215611f4457600080fd5b8451611f4f81612626565b6020860151909450611f6081612636565b6040860151909350611f7181612636565b6060860151909250611f8281612636565b939692955090935050565b600060208284031215611f9f57600080fd5b5035919050565b60008060408385031215611fb957600080fd5b8235915060208084013567ffffffffffffffff80821115611fd957600080fd5b818601915086601f830112611fed57600080fd5b813581811115611fff57611fff6125f7565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715612042576120426125f7565b604052828152858101935084860182860187018b101561206157600080fd5b600095505b83861015612084578035855260019590950194938601938601612066565b508096505050505050509250929050565b60008060008060008060c087890312156120ae57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000602082840312156120f157600080fd5b813561173881612636565b60008060006060848603121561211157600080fd5b833561211c81612636565b9250602084013561212c81612626565b9150604084013561213c81612636565b809150509250925092565b6000806040838503121561215a57600080fd5b8235611e5e81612636565b60008060008060008060008060006101208a8c03121561218457600080fd5b895161218f81612636565b60208b01519099506121a081612636565b60408b01519098506121b181612636565b60608b01519097506121c281612636565b60808b01519096506121d381612636565b94506121e160a08b01611de9565b93506121ef60c08b01611de9565b92506121fd60e08b01611de9565b915061220c6101008b01611de9565b90509295985092959850929598565b600080600080600060a0868803121561223357600080fd5b853561223e81612636565b9450602086013561224e81612636565b935061225c60408701611dfc565b92506060860135915061227160808701611dfc565b90509295509295909350565b600080600080600060a0868803121561229557600080fd5b61229e86611e0d565b945060208601519350604086015192506060860151915061227160808701611e0d565b600060208083528351808285015260005b818110156122ee578581018301518582016040015282016122d2565b81811115612300576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000604082018483526020604081850152818551808452606086019150828701935060005b8181101561237557845183529383019391830191600101612359565b5090979650505050505050565b6000821982111561239557612395612599565b500190565b600063ffffffff8083168185168083038211156123b9576123b9612599565b01949350505050565b600060ff821660ff84168060ff038211156123df576123df612599565b019392505050565b6000826123f6576123f66125c8565b500490565b600063ffffffff80841680612412576124126125c8565b92169190910492915050565b600181815b8085111561247757817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561245d5761245d612599565b8085161561246a57918102915b93841c9390800290612423565b509250929050565b600061173883836000826124955750600161093c565b816124a25750600061093c565b81600181146124b857600281146124c2576124de565b600191505061093c565b60ff8411156124d3576124d3612599565b50506001821b61093c565b5060208310610133831016604e8410600b8410161715612501575081810a61093c565b61250b838361241e565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561253d5761253d612599565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561257d5761257d612599565b500290565b60008282101561259457612594612599565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61ffff8116811461126557600080fd5b63ffffffff8116811461126557600080fdfea164736f6c6343000806000a", } var VRFV2WrapperABI = VRFV2WrapperMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go index 9fd983e2cf0..91112ff856f 100644 --- a/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go +++ b/core/gethwrappers/generated/vrfv2plus_client/vrfv2plus_client.go @@ -30,7 +30,7 @@ var ( var VRFV2PlusClientMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"EXTRA_ARGS_V1_TAG\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6088610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063f7514ab4146038575b600080fd5b605e7f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa81565b6040516001600160e01b0319909116815260200160405180910390f3fea164736f6c6343000806000a", + Bin: "0x60a0610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063f7514ab4146038575b600080fd5b605e7f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa81565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f3fea164736f6c6343000806000a", } var VRFV2PlusClientABI = VRFV2PlusClientMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go index 043ee6e303f..c0c19a1134c 100644 --- a/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go +++ b/core/gethwrappers/generated/vrfv2plus_malicious_migrator/vrfv2plus_malicious_migrator.go @@ -29,7 +29,7 @@ var ( ) var VRFV2PlusMaliciousMigratorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Bin: "0x608060405234801561001057600080fd5b506040516102e03803806102e083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61024d806100936000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80638ea9811714610030575b600080fd5b61004361003e36600461012a565b610045565b005b600080546040805160c081018252838152602080820185905281830185905260608201859052608082018590528251908101835293845260a0810193909352517f9b1c385e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911691639b1c385e916100d49190600401610180565b602060405180830381600087803b1580156100ee57600080fd5b505af1158015610102573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101269190610167565b5050565b60006020828403121561013c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461016057600080fd5b9392505050565b60006020828403121561017957600080fd5b5051919050565b6000602080835283518184015280840151604084015261ffff6040850151166060840152606084015163ffffffff80821660808601528060808701511660a0860152505060a084015160c08085015280518060e086015260005b818110156101f757828101840151868201610100015283016101da565b8181111561020a57600061010083880101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016939093016101000194935050505056fea164736f6c6343000806000a", } @@ -169,16 +169,16 @@ func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorTransactorRaw) Tran return _VRFV2PlusMaliciousMigrator.Contract.contract.Transact(opts, method, params...) } -func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorTransactor) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusMaliciousMigrator.contract.Transact(opts, "setCoordinator", _vrfCoordinator) +func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorTransactor) SetCoordinator(opts *bind.TransactOpts, arg0 common.Address) (*types.Transaction, error) { + return _VRFV2PlusMaliciousMigrator.contract.Transact(opts, "setCoordinator", arg0) } -func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorSession) SetCoordinator(_vrfCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusMaliciousMigrator.Contract.SetCoordinator(&_VRFV2PlusMaliciousMigrator.TransactOpts, _vrfCoordinator) +func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorSession) SetCoordinator(arg0 common.Address) (*types.Transaction, error) { + return _VRFV2PlusMaliciousMigrator.Contract.SetCoordinator(&_VRFV2PlusMaliciousMigrator.TransactOpts, arg0) } -func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorTransactorSession) SetCoordinator(_vrfCoordinator common.Address) (*types.Transaction, error) { - return _VRFV2PlusMaliciousMigrator.Contract.SetCoordinator(&_VRFV2PlusMaliciousMigrator.TransactOpts, _vrfCoordinator) +func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigratorTransactorSession) SetCoordinator(arg0 common.Address) (*types.Transaction, error) { + return _VRFV2PlusMaliciousMigrator.Contract.SetCoordinator(&_VRFV2PlusMaliciousMigrator.TransactOpts, arg0) } func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigrator) Address() common.Address { @@ -186,7 +186,7 @@ func (_VRFV2PlusMaliciousMigrator *VRFV2PlusMaliciousMigrator) Address() common. } type VRFV2PlusMaliciousMigratorInterface interface { - SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) + SetCoordinator(opts *bind.TransactOpts, arg0 common.Address) (*types.Transaction, error) Address() common.Address } diff --git a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go index d5a58fa0f9a..72364701395 100644 --- a/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go +++ b/core/gethwrappers/generated/vrfv2plus_reverting_example/vrfv2plus_reverting_example.go @@ -32,7 +32,7 @@ var ( var VRFV2PlusRevertingExampleMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"createSubscriptionAndFund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"subId\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"minReqConfs\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomness\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_gasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_randomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_subId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"name\":\"updateSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b506040516200121f3803806200121f8339810160408190526200003491620001cc565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000103565b5050600280546001600160a01b03199081166001600160a01b0394851617909155600580548216958416959095179094555060068054909316911617905562000204565b6001600160a01b0381163314156200015e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001c757600080fd5b919050565b60008060408385031215620001e057600080fd5b620001eb83620001af565b9150620001fb60208401620001af565b90509250929050565b61100b80620002146000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638ea981171161008c578063e89e106a11610066578063e89e106a146101e6578063f08c5daa146101ef578063f2fde38b146101f8578063f6eaffc81461020b57600080fd5b80638ea98117146101a05780639eccacf6146101b3578063cf62c8ab146101d357600080fd5b806336bfffed116100c857806336bfffed1461013d578063706da1ca1461015057806379ba5097146101595780638da5cb5b1461016157600080fd5b80631fe543e3146100ef5780632e75964e146101045780632fa4e4421461012a575b600080fd5b6101026100fd366004610cdf565b61021e565b005b610117610112366004610c4d565b6102a4565b6040519081526020015b60405180910390f35b610102610138366004610d83565b6103a1565b61010261014b366004610b87565b6104c3565b61011760075481565b6101026105fb565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b6101026101ae366004610b65565b6106f8565b60025461017b9073ffffffffffffffffffffffffffffffffffffffff1681565b6101026101e1366004610d83565b610803565b61011760045481565b61011760085481565b610102610206366004610b65565b61097a565b610117610219366004610cad565b61098e565b60025473ffffffffffffffffffffffffffffffffffffffff163314610296576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6102a08282600080fd5b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260055492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061033f908490600401610e68565b602060405180830381600087803b15801561035957600080fd5b505af115801561036d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103919190610cc6565b6004819055979650505050505050565b60075461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161028d565b60065460055460075460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161047193929190610e1c565b602060405180830381600087803b15801561048b57600080fd5b505af115801561049f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a09190610c2b565b60075461052c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161028d565b60005b81518110156102a057600554600754835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061057257610572610fa0565b60200260200101516040518363ffffffff1660e01b81526004016105b692919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b1580156105d057600080fd5b505af11580156105e4573d6000803e3d6000fd5b5050505080806105f390610f40565b91505061052f565b60015473ffffffffffffffffffffffffffffffffffffffff16331461067c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161028d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610738575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156107bc573361075d60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161028d565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60075461040a57600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561087457600080fd5b505af1158015610888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ac9190610cc6565b60078190556005546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561092257600080fd5b505af1158015610936573d6000803e3d6000fd5b5050505060065460055460075460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610444919060200190815260200190565b6109826109af565b61098b81610a32565b50565b6003818154811061099e57600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161028d565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610ab2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161028d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b4c57600080fd5b919050565b803563ffffffff81168114610b4c57600080fd5b600060208284031215610b7757600080fd5b610b8082610b28565b9392505050565b60006020808385031215610b9a57600080fd5b823567ffffffffffffffff811115610bb157600080fd5b8301601f81018513610bc257600080fd5b8035610bd5610bd082610f1c565b610ecd565b80828252848201915084840188868560051b8701011115610bf557600080fd5b600094505b83851015610c1f57610c0b81610b28565b835260019490940193918501918501610bfa565b50979650505050505050565b600060208284031215610c3d57600080fd5b81518015158114610b8057600080fd5b600080600080600060a08688031215610c6557600080fd5b8535945060208601359350604086013561ffff81168114610c8557600080fd5b9250610c9360608701610b51565b9150610ca160808701610b51565b90509295509295909350565b600060208284031215610cbf57600080fd5b5035919050565b600060208284031215610cd857600080fd5b5051919050565b60008060408385031215610cf257600080fd5b8235915060208084013567ffffffffffffffff811115610d1157600080fd5b8401601f81018613610d2257600080fd5b8035610d30610bd082610f1c565b80828252848201915084840189868560051b8701011115610d5057600080fd5b600094505b83851015610d73578035835260019490940193918501918501610d55565b5080955050505050509250929050565b600060208284031215610d9557600080fd5b81356bffffffffffffffffffffffff81168114610b8057600080fd5b6000815180845260005b81811015610dd757602081850181015186830182015201610dbb565b81811115610de9576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610e5f6060830184610db1565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ec560e0840182610db1565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f1457610f14610fcf565b604052919050565b600067ffffffffffffffff821115610f3657610f36610fcf565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f99577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + Bin: "0x60806040523480156200001157600080fd5b5060405162001215380380620012158339810160408190526200003491620001c2565b8133806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000f9565b5050600280546001600160a01b039384166001600160a01b0319918216179091556005805494909316931692909217905550620001fa9050565b6001600160a01b038116331415620001545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001bd57600080fd5b919050565b60008060408385031215620001d657600080fd5b620001e183620001a5565b9150620001f160208401620001a5565b90509250929050565b61100b806200020a6000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638ea981171161008c578063e89e106a11610066578063e89e106a146101e6578063f08c5daa146101ef578063f2fde38b146101f8578063f6eaffc81461020b57600080fd5b80638ea98117146101a05780639eccacf6146101b3578063cf62c8ab146101d357600080fd5b806336bfffed116100c857806336bfffed1461013d578063706da1ca1461015057806379ba5097146101595780638da5cb5b1461016157600080fd5b80631fe543e3146100ef5780632e75964e146101045780632fa4e4421461012a575b600080fd5b6101026100fd366004610cdf565b61021e565b005b610117610112366004610c4d565b6102a4565b6040519081526020015b60405180910390f35b610102610138366004610d83565b6103a1565b61010261014b366004610b87565b6104c3565b61011760065481565b6101026105fb565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b6101026101ae366004610b65565b6106f8565b60025461017b9073ffffffffffffffffffffffffffffffffffffffff1681565b6101026101e1366004610d83565b610803565b61011760045481565b61011760075481565b610102610206366004610b65565b61097a565b610117610219366004610cad565b61098e565b60025473ffffffffffffffffffffffffffffffffffffffff163314610296576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6102a08282600080fd5b5050565b6040805160c081018252868152602080820187905261ffff86168284015263ffffffff80861660608401528416608083015282519081018352600080825260a083019190915260025492517f9b1c385e000000000000000000000000000000000000000000000000000000008152909273ffffffffffffffffffffffffffffffffffffffff1690639b1c385e9061033f908490600401610e68565b602060405180830381600087803b15801561035957600080fd5b505af115801561036d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103919190610cc6565b6004819055979650505050505050565b60065461040a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f737562206e6f7420736574000000000000000000000000000000000000000000604482015260640161028d565b60055460025460065460408051602081019290925273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591015b6040516020818303038152906040526040518463ffffffff1660e01b815260040161047193929190610e1c565b602060405180830381600087803b15801561048b57600080fd5b505af115801561049f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102a09190610c2b565b60065461052c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f7375624944206e6f742073657400000000000000000000000000000000000000604482015260640161028d565b60005b81518110156102a057600254600654835173ffffffffffffffffffffffffffffffffffffffff9092169163bec4c08c919085908590811061057257610572610fa0565b60200260200101516040518363ffffffff1660e01b81526004016105b692919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b1580156105d057600080fd5b505af11580156105e4573d6000803e3d6000fd5b5050505080806105f390610f40565b91505061052f565b60015473ffffffffffffffffffffffffffffffffffffffff16331461067c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161028d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610738575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156107bc573361075d60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161028d565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60065461040a57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561087457600080fd5b505af1158015610888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ac9190610cc6565b60068190556002546040517fbec4c08c000000000000000000000000000000000000000000000000000000008152600481019290925230602483015273ffffffffffffffffffffffffffffffffffffffff169063bec4c08c90604401600060405180830381600087803b15801561092257600080fd5b505af1158015610936573d6000803e3d6000fd5b5050505060055460025460065460405173ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591610444919060200190815260200190565b6109826109af565b61098b81610a32565b50565b6003818154811061099e57600080fd5b600091825260209091200154905081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161028d565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610ab2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161028d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b4c57600080fd5b919050565b803563ffffffff81168114610b4c57600080fd5b600060208284031215610b7757600080fd5b610b8082610b28565b9392505050565b60006020808385031215610b9a57600080fd5b823567ffffffffffffffff811115610bb157600080fd5b8301601f81018513610bc257600080fd5b8035610bd5610bd082610f1c565b610ecd565b80828252848201915084840188868560051b8701011115610bf557600080fd5b600094505b83851015610c1f57610c0b81610b28565b835260019490940193918501918501610bfa565b50979650505050505050565b600060208284031215610c3d57600080fd5b81518015158114610b8057600080fd5b600080600080600060a08688031215610c6557600080fd5b8535945060208601359350604086013561ffff81168114610c8557600080fd5b9250610c9360608701610b51565b9150610ca160808701610b51565b90509295509295909350565b600060208284031215610cbf57600080fd5b5035919050565b600060208284031215610cd857600080fd5b5051919050565b60008060408385031215610cf257600080fd5b8235915060208084013567ffffffffffffffff811115610d1157600080fd5b8401601f81018613610d2257600080fd5b8035610d30610bd082610f1c565b80828252848201915084840189868560051b8701011115610d5057600080fd5b600094505b83851015610d73578035835260019490940193918501918501610d55565b5080955050505050509250929050565b600060208284031215610d9557600080fd5b81356bffffffffffffffffffffffff81168114610b8057600080fd5b6000815180845260005b81811015610dd757602081850181015186830182015201610dbb565b81811115610de9576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff83166020820152606060408201526000610e5f6060830184610db1565b95945050505050565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ec560e0840182610db1565b949350505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610f1457610f14610fcf565b604052919050565b600067ffffffffffffffff821115610f3657610f36610fcf565b5060051b60200190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610f99577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusRevertingExampleABI = VRFV2PlusRevertingExampleMetaData.ABI diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go index 0fa54876b7c..d7894c576e3 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper/vrfv2plus_wrapper.go @@ -31,8 +31,8 @@ var ( ) var VRFV2PlusWrapperMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractExtendedVRFCoordinatorV2PlusInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"requestGasPrice\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_link\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_linkNativeFeed\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"_wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"name\":\"setLINK\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLinkNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040526004805463ffffffff60a01b1916609160a21b1790553480156200002757600080fd5b50604051620030e7380380620030e78339810160408190526200004a9162000317565b803380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d557620000d5816200024e565b5050600280546001600160a01b0319166001600160a01b03938416179055508316156200011857600380546001600160a01b0319166001600160a01b0385161790555b6001600160a01b038216156200014457600480546001600160a01b0319166001600160a01b0384161790555b806001600160a01b03166080816001600160a01b031660601b815250506000816001600160a01b031663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200019f57600080fd5b505af1158015620001b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001da919062000361565b60a0819052604051632fb1302360e21b8152600481018290523060248201529091506001600160a01b0383169063bec4c08c90604401600060405180830381600087803b1580156200022b57600080fd5b505af115801562000240573d6000803e3d6000fd5b50505050505050506200037b565b6001600160a01b038116331415620002a95760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200031257600080fd5b919050565b6000806000606084860312156200032d57600080fd5b6200033884620002fa565b92506200034860208501620002fa565b91506200035860408501620002fa565b90509250925092565b6000602082840312156200037457600080fd5b5051919050565b60805160601c60a051612d12620003d5600039600081816101ef01528181610d2301526115e40152600081816102f901528181610ded0152818161166b0152818161197301528181611a540152611aef0152612d126000f3fe6080604052600436106101d85760003560e01c80638da5cb5b11610102578063c15ce4d711610095578063f254bdc711610064578063f254bdc7146106ff578063f2fde38b1461072c578063f3fef3a31461074c578063fc2a88c31461076c57600080fd5b8063c15ce4d7146105c0578063c3f909d4146105e0578063cdd8d88514610688578063da4f5e6d146106d257600080fd5b8063a3907d71116100d1578063a3907d711461054c578063a4c0ed3614610561578063a608a1e114610581578063bf17e559146105a057600080fd5b80638da5cb5b146104b45780638ea98117146104df5780639eccacf6146104ff578063a02e06161461052c57600080fd5b80634306d3541161017a57806362a504fc1161014957806362a504fc1461044c578063650596541461045f57806379ba50971461047f5780637fb5d19d1461049457600080fd5b80634306d3541461034057806348baa1c5146103605780634b1609351461040257806357a8070a1461042257600080fd5b80631fe543e3116101b65780631fe543e3146102925780632f2770db146102b25780633255c456146102c75780633b2bcbf1146102e757600080fd5b8063030932bb146101dd57806307b18bde14610224578063181f5a7714610246575b600080fd5b3480156101e957600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561023057600080fd5b5061024461023f36600461263a565b610782565b005b34801561025257600080fd5b50604080518082018252601281527f56524656325772617070657220312e302e3000000000000000000000000000006020820152905161021b9190612aa8565b34801561029e57600080fd5b506102446102ad36600461279e565b61085e565b3480156102be57600080fd5b506102446108df565b3480156102d357600080fd5b506102116102e236600461293f565b610915565b3480156102f357600080fd5b5061031b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021b565b34801561034c57600080fd5b5061021161035b3660046128d7565b610a0d565b34801561036c57600080fd5b506103cb61037b366004612785565b600b602052600090815260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff82169174010000000000000000000000000000000000000000900463ffffffff169083565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff90921660208401529082015260600161021b565b34801561040e57600080fd5b5061021161041d3660046128d7565b610b14565b34801561042e57600080fd5b5060065461043c9060ff1681565b604051901515815260200161021b565b61021161045a3660046128f4565b610c0b565b34801561046b57600080fd5b5061024461047a36600461261f565b610f1d565b34801561048b57600080fd5b50610244610f6c565b3480156104a057600080fd5b506102116104af36600461293f565b611069565b3480156104c057600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661031b565b3480156104eb57600080fd5b506102446104fa36600461261f565b61116f565b34801561050b57600080fd5b5060025461031b9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561053857600080fd5b5061024461054736600461261f565b61127a565b34801561055857600080fd5b50610244611319565b34801561056d57600080fd5b5061024461057c366004612664565b61134b565b34801561058d57600080fd5b5060065461043c90610100900460ff1681565b3480156105ac57600080fd5b506102446105bb3660046128d7565b6117cb565b3480156105cc57600080fd5b506102446105db366004612997565b611822565b3480156105ec57600080fd5b50600754600854600954600a546040805194855263ffffffff808516602087015264010000000085048116918601919091526c01000000000000000000000000840481166060860152700100000000000000000000000000000000840416608085015260ff74010000000000000000000000000000000000000000909304831660a085015260c08401919091521660e08201526101000161021b565b34801561069457600080fd5b506004546106bd9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161021b565b3480156106de57600080fd5b5060035461031b9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561070b57600080fd5b5060045461031b9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561073857600080fd5b5061024461074736600461261f565b611bfe565b34801561075857600080fd5b5061024461076736600461263a565b611c12565b34801561077857600080fd5b5061021160055481565b61078a611cfc565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146107e4576040519150601f19603f3d011682016040523d82523d6000602084013e6107e9565b606091505b5050905080610859576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e61746976650000000000000060448201526064015b60405180910390fd5b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146108d1576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610850565b6108db8282611d7f565b5050565b6108e7611cfc565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b60065460009060ff16610984576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610850565b600654610100900460ff16156109f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610850565b610a068363ffffffff1683611f6b565b9392505050565b60065460009060ff16610a7c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610850565b600654610100900460ff1615610aee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610850565b6000610af861207c565b9050610b0b8363ffffffff163a836121cb565b9150505b919050565b60065460009060ff16610b83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610850565b600654610100900460ff1615610bf5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610850565b610c058263ffffffff163a611f6b565b92915050565b600080610c17856122f8565b90506000610c2b8663ffffffff163a611f6b565b905080341015610c97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610850565b600a5460ff1663ffffffff85161115610d0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610850565b60006040518060c0016040528060095481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018761ffff1681526020016008600c9054906101000a900463ffffffff16858a610d709190612b7e565b610d7a9190612b7e565b63ffffffff1681526020018663ffffffff168152602001610dab604051806020016040528060011515815250612310565b90526040517f9b1c385e00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690639b1c385e90610e22908490600401612abb565b602060405180830381600087803b158015610e3c57600080fd5b505af1158015610e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e74919061270d565b6040805160608101825233815263ffffffff808b1660208084019182523a8486019081526000878152600b90925294902092518354915190921674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff9290921691909117178155905160019091015593505050509392505050565b610f25611cfc565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610fed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610850565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60065460009060ff166110d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610850565b600654610100900460ff161561114a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610850565b600061115461207c565b90506111678463ffffffff1684836121cb565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906111af575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561123357336111d460005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841660048201529183166024830152919091166044820152606401610850565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611282611cfc565b60035473ffffffffffffffffffffffffffffffffffffffff16156112d2576040517f2d118a6e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611321611cfc565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60065460ff166113b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e66696775726564000000000000006044820152606401610850565b600654610100900460ff1615611429576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c6564000000000000000000000000006044820152606401610850565b60035473ffffffffffffffffffffffffffffffffffffffff1633146114aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b0000000000000000006044820152606401610850565b600080806114ba848601866128f4565b92509250925060006114cb846122f8565b905060006114d761207c565b905060006114ec8663ffffffff163a846121cb565b905080891015611558576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f770000000000000000000000000000000000000000006044820152606401610850565b600a5460ff1663ffffffff851611156115cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f20686967680000000000000000000000000000006044820152606401610850565b60006040518060c0016040528060095481526020017f000000000000000000000000000000000000000000000000000000000000000081526020018761ffff1681526020016008600c9054906101000a900463ffffffff16868a6116319190612b7e565b61163b9190612b7e565b63ffffffff1681526020018663ffffffff16815260200160405180602001604052806000815250815250905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639b1c385e836040518263ffffffff1660e01b81526004016116c29190612abb565b602060405180830381600087803b1580156116dc57600080fd5b505af11580156116f0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611714919061270d565b6040805160608101825273ffffffffffffffffffffffffffffffffffffffff9e8f16815263ffffffff9a8b1660208083019182523a8385019081526000868152600b909252939020915182549151909c1674010000000000000000000000000000000000000000027fffffffffffffffff0000000000000000000000000000000000000000000000009091169b909f169a909a179d909d1789559b5160019098019790975550505060059790975550505050505050565b6117d3611cfc565b6004805463ffffffff90921674010000000000000000000000000000000000000000027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b61182a611cfc565b6008805460ff80861674010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff63ffffffff898116700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff918c166c0100000000000000000000000002919091167fffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffff909516949094179390931792909216919091179091556009839055600a80549183167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00928316179055600680549091166001179055604080517f088070f5000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169163088070f5916004828101926080929190829003018186803b1580156119b957600080fd5b505afa1580156119cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f19190612726565b50600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff929092169190911790555050604080517f043bd6ae00000000000000000000000000000000000000000000000000000000815290517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169163043bd6ae916004808301926020929190829003018186803b158015611aaf57600080fd5b505afa158015611ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae7919061270d565b6007819055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636b6feccc6040518163ffffffff1660e01b8152600401604080518083038186803b158015611b5257600080fd5b505afa158015611b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8a919061295d565b600880547fffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffff166801000000000000000063ffffffff938416027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff161764010000000093909216929092021790555050505050565b611c06611cfc565b611c0f816123cc565b50565b611c1a611cfc565b6003546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490529091169063a9059cbb90604401602060405180830381600087803b158015611c8e57600080fd5b505af1158015611ca2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc691906126eb565b6108db576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314611d7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610850565b565b6000828152600b602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835263ffffffff740100000000000000000000000000000000000000008304168387015260018401805495840195909552898852959094527fffffffffffffffff000000000000000000000000000000000000000000000000909316905592909255815116611e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610850565b600080631fe543e360e01b8585604051602401611e9b929190612b18565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000611f15846020015163ffffffff168560000151846124c2565b905080611f6357835160405173ffffffffffffffffffffffffffffffffffffffff9091169087907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b505050505050565b6004546000908190611f9a9074010000000000000000000000000000000000000000900463ffffffff1661250e565b60085463ffffffff7001000000000000000000000000000000008204811691611fd5916c010000000000000000000000009091041687612b66565b611fdf9190612b66565b611fe99085612c02565b611ff39190612b66565b60085490915081906000906064906120269074010000000000000000000000000000000000000000900460ff1682612ba6565b6120339060ff1684612c02565b61203d9190612bcb565b6008549091506000906120679068010000000000000000900463ffffffff1664e8d4a51000612c02565b6120719083612b66565b979650505050505050565b60085460048054604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009463ffffffff161515938593849373ffffffffffffffffffffffffffffffffffffffff9091169263feaf968c928281019260a0929190829003018186803b1580156120f857600080fd5b505afa15801561210c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213091906129f9565b509450909250849150508015612156575061214b8242612c3f565b60085463ffffffff16105b1561216057506007545b6000811215610a06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b20776569207072696365000000000000000000006044820152606401610850565b60045460009081906121fa9074010000000000000000000000000000000000000000900463ffffffff1661250e565b60085463ffffffff7001000000000000000000000000000000008204811691612235916c010000000000000000000000009091041688612b66565b61223f9190612b66565b6122499086612c02565b6122539190612b66565b905060008361226a83670de0b6b3a7640000612c02565b6122749190612bcb565b6008549091506000906064906122a59074010000000000000000000000000000000000000000900460ff1682612ba6565b6122b29060ff1684612c02565b6122bc9190612bcb565b6008549091506000906122e290640100000000900463ffffffff1664e8d4a51000612c02565b6122ec9083612b66565b98975050505050505050565b6000612305603f83612bdf565b610c05906001612b7e565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa8260405160240161234991511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b73ffffffffffffffffffffffffffffffffffffffff811633141561244c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610850565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a6113888110156124d457600080fd5b6113888103905084604082048203116124ec57600080fd5b50823b6124f857600080fd5b60008083516020850160008789f1949350505050565b60004661a4b1811480612523575062066eed81145b156125c7576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b15801561257157600080fd5b505afa158015612585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a9919061288d565b5050505091505083608c6125bd9190612b66565b6111679082612c02565b50600092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b0f57600080fd5b803560ff81168114610b0f57600080fd5b805169ffffffffffffffffffff81168114610b0f57600080fd5b60006020828403121561263157600080fd5b610a06826125d0565b6000806040838503121561264d57600080fd5b612656836125d0565b946020939093013593505050565b6000806000806060858703121561267a57600080fd5b612683856125d0565b935060208501359250604085013567ffffffffffffffff808211156126a757600080fd5b818701915087601f8301126126bb57600080fd5b8135818111156126ca57600080fd5b8860208285010111156126dc57600080fd5b95989497505060200194505050565b6000602082840312156126fd57600080fd5b81518015158114610a0657600080fd5b60006020828403121561271f57600080fd5b5051919050565b6000806000806080858703121561273c57600080fd5b845161274781612ce3565b602086015190945061275881612cf3565b604086015190935061276981612cf3565b606086015190925061277a81612cf3565b939692955090935050565b60006020828403121561279757600080fd5b5035919050565b600080604083850312156127b157600080fd5b8235915060208084013567ffffffffffffffff808211156127d157600080fd5b818601915086601f8301126127e557600080fd5b8135818111156127f7576127f7612cb4565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561283a5761283a612cb4565b604052828152858101935084860182860187018b101561285957600080fd5b600095505b8386101561287c57803585526001959095019493860193860161285e565b508096505050505050509250929050565b60008060008060008060c087890312156128a657600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000602082840312156128e957600080fd5b8135610a0681612cf3565b60008060006060848603121561290957600080fd5b833561291481612cf3565b9250602084013561292481612ce3565b9150604084013561293481612cf3565b809150509250925092565b6000806040838503121561295257600080fd5b823561265681612cf3565b6000806040838503121561297057600080fd5b825161297b81612cf3565b602084015190925061298c81612cf3565b809150509250929050565b600080600080600060a086880312156129af57600080fd5b85356129ba81612cf3565b945060208601356129ca81612cf3565b93506129d8604087016125f4565b9250606086013591506129ed608087016125f4565b90509295509295909350565b600080600080600060a08688031215612a1157600080fd5b612a1a86612605565b94506020860151935060408601519250606086015191506129ed60808701612605565b6000815180845260005b81811015612a6357602081850181015186830182015201612a47565b81811115612a75576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610a066020830184612a3d565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c08084015261116760e0840182612a3d565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015612b5957845183529383019391830191600101612b3d565b5090979650505050505050565b60008219821115612b7957612b79612c56565b500190565b600063ffffffff808316818516808303821115612b9d57612b9d612c56565b01949350505050565b600060ff821660ff84168060ff03821115612bc357612bc3612c56565b019392505050565b600082612bda57612bda612c85565b500490565b600063ffffffff80841680612bf657612bf6612c85565b92169190910492915050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612c3a57612c3a612c56565b500290565b600082821015612c5157612c51612c56565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61ffff81168114611c0f57600080fd5b63ffffffff81168114611c0f57600080fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_coordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FailedToTransferLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"expectedMinimumLength\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"actualLength\",\"type\":\"uint16\"}],\"name\":\"IncorrectExtraArgsLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LINKPaymentInRequestRandomWordsInNative\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativePaymentInOnTokenTransfer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"}],\"name\":\"OnlyOwnerOrCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"WrapperFulfillmentFailed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUBSCRIPTION_ID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"calculateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isLinkMode\",\"type\":\"bool\"}],\"name\":\"checkPaymentMode\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"enable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_requestGasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateRequestPriceNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"maxNumWords\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newCoordinator\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"requestRandomWordsInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_callbacks\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"requestGasPrice\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_configured\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_disabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fulfillmentTxSizeBytes\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_link\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_linkNativeFeed\",\"outputs\":[{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_vrfCoordinator\",\"outputs\":[{\"internalType\":\"contractIVRFCoordinatorV2Plus\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_wrapperGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_coordinatorGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"_wrapperPremiumPercentage\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"_maxNumWords\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"_stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"int256\",\"name\":\"_fallbackWeiPerUnitLink\",\"type\":\"int256\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"name\":\"setCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"size\",\"type\":\"uint32\"}],\"name\":\"setFulfillmentTxSize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"}],\"name\":\"setLINK\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"}],\"name\":\"setLinkNativeFeed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040526007805463ffffffff60201b1916650244000000001790553480156200002957600080fd5b506040516200366e3803806200366e8339810160408190526200004c9162000323565b803380600081620000a45760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d757620000d7816200025a565b5050600280546001600160a01b0319166001600160a01b03938416179055508316156200012857600680546001600160601b03166c010000000000000000000000006001600160a01b038616021790555b6001600160a01b038216156200016257600780546001600160601b03166c010000000000000000000000006001600160a01b038516021790555b6002546040805163288688f960e21b815290516000926001600160a01b03169163a21a23e491600480830192602092919082900301818787803b158015620001a957600080fd5b505af1158015620001be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001e491906200036d565b6080819052600254604051632fb1302360e21b8152600481018390523060248201529192506001600160a01b03169063bec4c08c90604401600060405180830381600087803b1580156200023757600080fd5b505af11580156200024c573d6000803e3d6000fd5b505050505050505062000387565b6001600160a01b038116331415620002b55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009b565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200031e57600080fd5b919050565b6000806000606084860312156200033957600080fd5b620003448462000306565b9250620003546020850162000306565b9150620003646040850162000306565b90509250925092565b6000602082840312156200038057600080fd5b5051919050565b6080516132b6620003b8600039600081816101fa015281816112690152818161183a0152611c3201526132b66000f3fe6080604052600436106101e35760003560e01c80639cfc058e11610102578063c3f909d411610095578063f254bdc711610064578063f254bdc71461072c578063f2fde38b14610769578063f3fef3a314610789578063fc2a88c3146107a957600080fd5b8063c3f909d4146105fc578063cdd8d88514610695578063ce5494bb146106cf578063da4f5e6d146106ef57600080fd5b8063a4c0ed36116100d1578063a4c0ed361461057d578063a608a1e11461059d578063bed41a93146105bc578063bf17e559146105dc57600080fd5b80639cfc058e146105085780639eccacf61461051b578063a02e061614610548578063a3907d711461056857600080fd5b806348baa1c51161017a57806379ba50971161014957806379ba5097146104675780637fb5d19d1461047c5780638da5cb5b1461049c5780638ea98117146104e857600080fd5b806348baa1c5146103325780634b160935146103fd57806357a8070a1461041d578063650596541461044757600080fd5b80631fe543e3116101b65780631fe543e3146102bd5780632f2770db146102dd5780633255c456146102f25780634306d3541461031257600080fd5b8063030932bb146101e857806307b18bde1461022f578063181f5a771461025157806318b6f4c81461029d575b600080fd5b3480156101f457600080fd5b5061021c7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561023b57600080fd5b5061024f61024a366004612a22565b6107bf565b005b34801561025d57600080fd5b50604080518082018252601281527f56524656325772617070657220312e302e300000000000000000000000000000602082015290516102269190612ebb565b3480156102a957600080fd5b5061024f6102b8366004612ac3565b61089b565b3480156102c957600080fd5b5061024f6102d8366004612b47565b610a12565b3480156102e957600080fd5b5061024f610a8f565b3480156102fe57600080fd5b5061021c61030d366004612d4a565b610ac5565b34801561031e57600080fd5b5061021c61032d366004612c4a565b610bbf565b34801561033e57600080fd5b506103bc61034d366004612b15565b60096020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000810463ffffffff16907801000000000000000000000000000000000000000000000000900467ffffffffffffffff1683565b6040805173ffffffffffffffffffffffffffffffffffffffff909416845263ffffffff909216602084015267ffffffffffffffff1690820152606001610226565b34801561040957600080fd5b5061021c610418366004612c4a565b610cc6565b34801561042957600080fd5b506008546104379060ff1681565b6040519015158152602001610226565b34801561045357600080fd5b5061024f610462366004612a07565b610db7565b34801561047357600080fd5b5061024f610e02565b34801561048857600080fd5b5061021c610497366004612d4a565b610eff565b3480156104a857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610226565b3480156104f457600080fd5b5061024f610503366004612a07565b611005565b61021c610516366004612c65565b611110565b34801561052757600080fd5b506002546104c39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561055457600080fd5b5061024f610563366004612a07565b6114a5565b34801561057457600080fd5b5061024f611550565b34801561058957600080fd5b5061024f610598366004612a4c565b611582565b3480156105a957600080fd5b5060085461043790610100900460ff1681565b3480156105c857600080fd5b5061024f6105d7366004612d66565b611a62565b3480156105e857600080fd5b5061024f6105f7366004612c4a565b611bb8565b34801561060857600080fd5b506005546006546007546008546003546040805195865263ffffffff8086166020880152640100000000860481169187019190915268010000000000000000948590048116606087015280841660808701529390920490921660a084015260ff620100008304811660c085015260e084019190915263010000009091041661010082015261012001610226565b3480156106a157600080fd5b506007546106ba90640100000000900463ffffffff1681565b60405163ffffffff9091168152602001610226565b3480156106db57600080fd5b5061024f6106ea366004612a07565b611bff565b3480156106fb57600080fd5b506006546104c3906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561073857600080fd5b506007546104c3906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561077557600080fd5b5061024f610784366004612a07565b611cb5565b34801561079557600080fd5b5061024f6107a4366004612a22565b611cc9565b3480156107b557600080fd5b5061021c60045481565b6107c7611dc4565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610821576040519150601f19603f3d011682016040523d82523d6000602084013e610826565b606091505b5050905080610896576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6661696c656420746f207769746864726177206e61746976650000000000000060448201526064015b60405180910390fd5b505050565b81516108dc57806108d8576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b81516024111561092d5781516040517f51200dce00000000000000000000000000000000000000000000000000000000815261088d9160249160040161ffff92831681529116602082015260400190565b6000826023815181106109425761094261323d565b6020910101517fff00000000000000000000000000000000000000000000000000000000000000167f01000000000000000000000000000000000000000000000000000000000000001490508080156109985750815b156109cf576040517f6048aa6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580156109db575081155b15610896576040517f6b81746e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff163314610a85576002546040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff909116602482015260440161088d565b6108d88282611e47565b610a97611dc4565b600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b60085460009060ff16610b34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161088d565b600854610100900460ff1615610ba6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161088d565b610bb68363ffffffff168361202f565b90505b92915050565b60085460009060ff16610c2e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161088d565b600854610100900460ff1615610ca0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161088d565b6000610caa612105565b9050610cbd8363ffffffff163a8361226c565b9150505b919050565b60085460009060ff16610d35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161088d565b600854610100900460ff1615610da7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161088d565b610bb98263ffffffff163a61202f565b610dbf611dc4565b6007805473ffffffffffffffffffffffffffffffffffffffff9092166c01000000000000000000000000026bffffffffffffffffffffffff909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161088d565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60085460009060ff16610f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161088d565b600854610100900460ff1615610fe0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161088d565b6000610fea612105565b9050610ffd8463ffffffff16848361226c565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611045575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156110c9573361106a60005473ffffffffffffffffffffffffffffffffffffffff1690565b6002546040517f061db9c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384166004820152918316602483015291909116604482015260640161088d565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600061115183838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250925061089b915050565b600061115c8761235e565b905060006111708863ffffffff163a61202f565b9050803410156111dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f77000000000000000000000000000000000000000000604482015260640161088d565b6008546301000000900460ff1663ffffffff87161115611258576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f2068696768000000000000000000000000000000604482015260640161088d565b6040805160c08101825260035481527f0000000000000000000000000000000000000000000000000000000000000000602082015261ffff89169181019190915260075460009190606082019063ffffffff166112b5868d612fe0565b6112bf9190612fe0565b63ffffffff1681526020018863ffffffff16815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506002546040517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff1690639b1c385e90611365908490600401612ece565b602060405180830381600087803b15801561137f57600080fd5b505af1158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b79190612b2e565b6040805160608101825233815263ffffffff808d16602080840191825267ffffffffffffffff3a81168587019081526000888152600990935295909120935184549251955190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff9590931674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff91909116171792909216919091179055935050505095945050505050565b6114ad611dc4565b6006546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161561150d576040517f2d118a6e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9092166c01000000000000000000000000026bffffffffffffffffffffffff909216919091179055565b611558611dc4565b600880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055565b60085460ff166115ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f77726170706572206973206e6f7420636f6e6669677572656400000000000000604482015260640161088d565b600854610100900460ff1615611660576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f777261707065722069732064697361626c656400000000000000000000000000604482015260640161088d565b6006546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146116f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f6f6e6c792063616c6c61626c652066726f6d204c494e4b000000000000000000604482015260640161088d565b600080808061170285870187612cdb565b935093509350935061171581600161089b565b60006117208561235e565b9050600061172c612105565b905060006117418763ffffffff163a8461226c565b9050808a10156117ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f66656520746f6f206c6f77000000000000000000000000000000000000000000604482015260640161088d565b6008546301000000900460ff1663ffffffff86161115611829576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6e756d576f72647320746f6f2068696768000000000000000000000000000000604482015260640161088d565b6040805160c08101825260035481527f0000000000000000000000000000000000000000000000000000000000000000602082015261ffff88169181019190915260075460009190606082019063ffffffff16611886878c612fe0565b6118909190612fe0565b63ffffffff908116825288166020820152604090810187905260025490517f9b1c385e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690639b1c385e90611904908590600401612ece565b602060405180830381600087803b15801561191e57600080fd5b505af1158015611932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119569190612b2e565b905060405180606001604052808e73ffffffffffffffffffffffffffffffffffffffff1681526020018a63ffffffff1681526020013a67ffffffffffffffff168152506009600083815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050508060048190555050505050505050505050505050565b611a6a611dc4565b6007805463ffffffff9a8b167fffffffffffffffffffffffffffffffffffffffff00000000ffffffff000000009091161768010000000000000000998b168a02179055600880546003979097557fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff9096166201000060ff988916027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff161763010000009590971694909402959095177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117909355600680546005949094557fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff9187167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009094169390931764010000000094871694909402939093179290921691909316909102179055565b611bc0611dc4565b6007805463ffffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff909216919091179055565b611c07611dc4565b6002546040517f405b84fa0000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301529091169063405b84fa90604401600060405180830381600087803b158015611c9a57600080fd5b505af1158015611cae573d6000803e3d6000fd5b5050505050565b611cbd611dc4565b611cc681612376565b50565b611cd1611dc4565b6006546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526c010000000000000000000000009092049091169063a9059cbb90604401602060405180830381600087803b158015611d5657600080fd5b505af1158015611d6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8e9190612aa6565b6108d8576040517f7c07fc4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314611e45576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161088d565b565b60008281526009602081815260408084208151606081018352815473ffffffffffffffffffffffffffffffffffffffff808216835274010000000000000000000000000000000000000000820463ffffffff1683870152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1693820193909352878652939092529290558051909116611f41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161088d565b600080631fe543e360e01b8585604051602401611f5f929190612f2b565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000611fd9846020015163ffffffff1685600001518461246c565b90508061202757835160405173ffffffffffffffffffffffffffffffffffffffff9091169087907fc551b83c151f2d1c7eeb938ac59008e0409f1c1dc1e2f112449d4d79b458902290600090a35b505050505050565b600754600090819061204e90640100000000900463ffffffff166124b8565b60075463ffffffff680100000000000000008204811691612070911687612fc8565b61207a9190612fc8565b612084908561318b565b61208e9190612fc8565b60085490915081906000906064906120af9062010000900460ff1682613008565b6120bc9060ff168461318b565b6120c6919061302d565b6006549091506000906120f09068010000000000000000900463ffffffff1664e8d4a5100061318b565b6120fa9083612fc8565b979650505050505050565b600654600754604080517ffeaf968c000000000000000000000000000000000000000000000000000000008152905160009363ffffffff16151592849283926c0100000000000000000000000090920473ffffffffffffffffffffffffffffffffffffffff169163feaf968c9160048082019260a092909190829003018186803b15801561219257600080fd5b505afa1580156121a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ca9190612e00565b5094509092508491505080156121f057506121e582426131c8565b60065463ffffffff16105b156121fa57506005545b6000811215612265576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964204c494e4b2077656920707269636500000000000000000000604482015260640161088d565b9392505050565b600754600090819061228b90640100000000900463ffffffff166124b8565b60075463ffffffff6801000000000000000082048116916122ad911688612fc8565b6122b79190612fc8565b6122c1908661318b565b6122cb9190612fc8565b90506000836122e283670de0b6b3a764000061318b565b6122ec919061302d565b60085490915060009060649061230b9062010000900460ff1682613008565b6123189060ff168461318b565b612322919061302d565b60065490915060009061234890640100000000900463ffffffff1664e8d4a5100061318b565b6123529083612fc8565b98975050505050505050565b600061236b603f83613041565b610bb9906001612fe0565b73ffffffffffffffffffffffffffffffffffffffff81163314156123f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161088d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005a61138881101561247e57600080fd5b61138881039050846040820482031161249657600080fd5b50823b6124a257600080fd5b60008083516020850160008789f1949350505050565b6000466124c481612588565b15612568576000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c06040518083038186803b15801561251257600080fd5b505afa158015612526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254a9190612c00565b5050505091505083608c61255e9190612fc8565b610ffd908261318b565b612571816125ab565b1561257f57610cbd836125e5565b50600092915050565b600061a4b182148061259c575062066eed82145b80610bb957505062066eee1490565b6000600a8214806125bd57506101a482145b806125ca575062aa37dc82145b806125d6575061210582145b80610bb957505062014a331490565b60008073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663519b4bd36040518163ffffffff1660e01b815260040160206040518083038186803b15801561264257600080fd5b505afa158015612656573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267a9190612b2e565b905060008061268981866131c8565b9050600061269882601061318b565b6126a384600461318b565b6126ad9190612fc8565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff16630c18c1626040518163ffffffff1660e01b815260040160206040518083038186803b15801561270b57600080fd5b505afa15801561271f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127439190612b2e565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663f45e65d86040518163ffffffff1660e01b815260040160206040518083038186803b1580156127a157600080fd5b505afa1580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d99190612b2e565b9050600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190612b2e565b9050600061287e82600a6130c5565b90506000818461288e8789612fc8565b612898908c61318b565b6128a2919061318b565b6128ac919061302d565b9b9a5050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cc157600080fd5b60008083601f8401126128f157600080fd5b50813567ffffffffffffffff81111561290957600080fd5b60208301915083602082850101111561292157600080fd5b9250929050565b600082601f83011261293957600080fd5b813567ffffffffffffffff8111156129535761295361326c565b61298460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612f79565b81815284602083860101111561299957600080fd5b816020850160208301376000918101602001919091529392505050565b803561ffff81168114610cc157600080fd5b803563ffffffff81168114610cc157600080fd5b803560ff81168114610cc157600080fd5b805169ffffffffffffffffffff81168114610cc157600080fd5b600060208284031215612a1957600080fd5b610bb6826128bb565b60008060408385031215612a3557600080fd5b612a3e836128bb565b946020939093013593505050565b60008060008060608587031215612a6257600080fd5b612a6b856128bb565b935060208501359250604085013567ffffffffffffffff811115612a8e57600080fd5b612a9a878288016128df565b95989497509550505050565b600060208284031215612ab857600080fd5b81516122658161329b565b60008060408385031215612ad657600080fd5b823567ffffffffffffffff811115612aed57600080fd5b612af985828601612928565b9250506020830135612b0a8161329b565b809150509250929050565b600060208284031215612b2757600080fd5b5035919050565b600060208284031215612b4057600080fd5b5051919050565b60008060408385031215612b5a57600080fd5b8235915060208084013567ffffffffffffffff80821115612b7a57600080fd5b818601915086601f830112612b8e57600080fd5b813581811115612ba057612ba061326c565b8060051b9150612bb1848301612f79565b8181528481019084860184860187018b1015612bcc57600080fd5b600095505b83861015612bef578035835260019590950194918601918601612bd1565b508096505050505050509250929050565b60008060008060008060c08789031215612c1957600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600060208284031215612c5c57600080fd5b610bb6826129c8565b600080600080600060808688031215612c7d57600080fd5b612c86866129c8565b9450612c94602087016129b6565b9350612ca2604087016129c8565b9250606086013567ffffffffffffffff811115612cbe57600080fd5b612cca888289016128df565b969995985093965092949392505050565b60008060008060808587031215612cf157600080fd5b612cfa856129c8565b9350612d08602086016129b6565b9250612d16604086016129c8565b9150606085013567ffffffffffffffff811115612d3257600080fd5b612d3e87828801612928565b91505092959194509250565b60008060408385031215612d5d57600080fd5b612a3e836129c8565b60008060008060008060008060006101208a8c031215612d8557600080fd5b612d8e8a6129c8565b9850612d9c60208b016129c8565b9750612daa60408b016129dc565b965060608a01359550612dbf60808b016129dc565b9450612dcd60a08b016129c8565b935060c08a01359250612de260e08b016129c8565b9150612df16101008b016129c8565b90509295985092959850929598565b600080600080600060a08688031215612e1857600080fd5b612e21866129ed565b9450602086015193506040860151925060608601519150612e44608087016129ed565b90509295509295909350565b6000815180845260005b81811015612e7657602081850181015186830182015201612e5a565b81811115612e88576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610bb66020830184612e50565b60208152815160208201526020820151604082015261ffff60408301511660608201526000606083015163ffffffff80821660808501528060808601511660a0850152505060a083015160c080840152610ffd60e0840182612e50565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015612f6c57845183529383019391830191600101612f50565b5090979650505050505050565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612fc057612fc061326c565b604052919050565b60008219821115612fdb57612fdb6131df565b500190565b600063ffffffff808316818516808303821115612fff57612fff6131df565b01949350505050565b600060ff821660ff84168060ff03821115613025576130256131df565b019392505050565b60008261303c5761303c61320e565b500490565b600063ffffffff808416806130585761305861320e565b92169190910492915050565b600181815b808511156130bd57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156130a3576130a36131df565b808516156130b057918102915b93841c9390800290613069565b509250929050565b6000610bb683836000826130db57506001610bb9565b816130e857506000610bb9565b81600181146130fe576002811461310857613124565b6001915050610bb9565b60ff841115613119576131196131df565b50506001821b610bb9565b5060208310610133831016604e8410600b8410161715613147575081810a610bb9565b6131518383613064565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613183576131836131df565b029392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156131c3576131c36131df565b500290565b6000828210156131da576131da6131df565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8015158114611cc657600080fdfea164736f6c6343000806000a", } var VRFV2PlusWrapperABI = VRFV2PlusWrapperMetaData.ABI @@ -171,28 +171,6 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorRaw) Transact(opts *bind.Tran return _VRFV2PlusWrapper.Contract.contract.Transact(opts, method, params...) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) COORDINATOR(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFV2PlusWrapper.contract.Call(opts, &out, "COORDINATOR") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) COORDINATOR() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.COORDINATOR(&_VRFV2PlusWrapper.CallOpts) -} - -func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) COORDINATOR() (common.Address, error) { - return _VRFV2PlusWrapper.Contract.COORDINATOR(&_VRFV2PlusWrapper.CallOpts) -} - func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) SUBSCRIPTIONID(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _VRFV2PlusWrapper.contract.Call(opts, &out, "SUBSCRIPTION_ID") @@ -259,6 +237,26 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) CalculateRequestPriceNat return _VRFV2PlusWrapper.Contract.CalculateRequestPriceNative(&_VRFV2PlusWrapper.CallOpts, _callbackGasLimit) } +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) CheckPaymentMode(opts *bind.CallOpts, extraArgs []byte, isLinkMode bool) error { + var out []interface{} + err := _VRFV2PlusWrapper.contract.Call(opts, &out, "checkPaymentMode", extraArgs, isLinkMode) + + if err != nil { + return err + } + + return err + +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) CheckPaymentMode(extraArgs []byte, isLinkMode bool) error { + return _VRFV2PlusWrapper.Contract.CheckPaymentMode(&_VRFV2PlusWrapper.CallOpts, extraArgs, isLinkMode) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperCallerSession) CheckPaymentMode(extraArgs []byte, isLinkMode bool) error { + return _VRFV2PlusWrapper.Contract.CheckPaymentMode(&_VRFV2PlusWrapper.CallOpts, extraArgs, isLinkMode) +} + func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) EstimateRequestPrice(opts *bind.CallOpts, _callbackGasLimit uint32, _requestGasPriceWei *big.Int) (*big.Int, error) { var out []interface{} err := _VRFV2PlusWrapper.contract.Call(opts, &out, "estimateRequestPrice", _callbackGasLimit, _requestGasPriceWei) @@ -317,11 +315,12 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) GetConfig(opts *bind.CallOpts) outstruct.FallbackWeiPerUnitLink = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.StalenessSeconds = *abi.ConvertType(out[1], new(uint32)).(*uint32) outstruct.FulfillmentFlatFeeLinkPPM = *abi.ConvertType(out[2], new(uint32)).(*uint32) - outstruct.WrapperGasOverhead = *abi.ConvertType(out[3], new(uint32)).(*uint32) - outstruct.CoordinatorGasOverhead = *abi.ConvertType(out[4], new(uint32)).(*uint32) - outstruct.WrapperPremiumPercentage = *abi.ConvertType(out[5], new(uint8)).(*uint8) - outstruct.KeyHash = *abi.ConvertType(out[6], new([32]byte)).(*[32]byte) - outstruct.MaxNumWords = *abi.ConvertType(out[7], new(uint8)).(*uint8) + outstruct.FulfillmentFlatFeeNativePPM = *abi.ConvertType(out[3], new(uint32)).(*uint32) + outstruct.WrapperGasOverhead = *abi.ConvertType(out[4], new(uint32)).(*uint32) + outstruct.CoordinatorGasOverhead = *abi.ConvertType(out[5], new(uint32)).(*uint32) + outstruct.WrapperPremiumPercentage = *abi.ConvertType(out[6], new(uint8)).(*uint8) + outstruct.KeyHash = *abi.ConvertType(out[7], new([32]byte)).(*[32]byte) + outstruct.MaxNumWords = *abi.ConvertType(out[8], new(uint8)).(*uint8) return *outstruct, err @@ -396,7 +395,7 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperCaller) SCallbacks(opts *bind.CallOpts, outstruct.CallbackAddress = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) outstruct.CallbackGasLimit = *abi.ConvertType(out[1], new(uint32)).(*uint32) - outstruct.RequestGasPrice = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.RequestGasPrice = *abi.ConvertType(out[2], new(uint64)).(*uint64) return *outstruct, err @@ -604,6 +603,18 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) Enable() (*types.Tra return _VRFV2PlusWrapper.Contract.Enable(&_VRFV2PlusWrapper.TransactOpts) } +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) Migrate(opts *bind.TransactOpts, newCoordinator common.Address) (*types.Transaction, error) { + return _VRFV2PlusWrapper.contract.Transact(opts, "migrate", newCoordinator) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) Migrate(newCoordinator common.Address) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.Migrate(&_VRFV2PlusWrapper.TransactOpts, newCoordinator) +} + +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) Migrate(newCoordinator common.Address) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.Migrate(&_VRFV2PlusWrapper.TransactOpts, newCoordinator) +} + func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) OnTokenTransfer(opts *bind.TransactOpts, _sender common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) { return _VRFV2PlusWrapper.contract.Transact(opts, "onTokenTransfer", _sender, _amount, _data) } @@ -628,28 +639,28 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) RawFulfillRandomWord return _VRFV2PlusWrapper.Contract.RawFulfillRandomWords(&_VRFV2PlusWrapper.TransactOpts, requestId, randomWords) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "requestRandomWordsInNative", _callbackGasLimit, _requestConfirmations, _numWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) { + return _VRFV2PlusWrapper.contract.Transact(opts, "requestRandomWordsInNative", _callbackGasLimit, _requestConfirmations, _numWords, extraArgs) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) RequestRandomWordsInNative(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) RequestRandomWordsInNative(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, extraArgs) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) RequestRandomWordsInNative(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) RequestRandomWordsInNative(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.RequestRandomWordsInNative(&_VRFV2PlusWrapper.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, extraArgs) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8) (*types.Transaction, error) { - return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.contract.Transact(opts, "setConfig", _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) } -func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8) (*types.Transaction, error) { - return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords) +func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactorSession) SetConfig(_wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) { + return _VRFV2PlusWrapper.Contract.SetConfig(&_VRFV2PlusWrapper.TransactOpts, _wrapperGasOverhead, _coordinatorGasOverhead, _wrapperPremiumPercentage, _keyHash, _maxNumWords, _stalenessSeconds, _fallbackWeiPerUnitLink, _fulfillmentFlatFeeLinkPPM, _fulfillmentFlatFeeNativePPM) } func (_VRFV2PlusWrapper *VRFV2PlusWrapperTransactor) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) { @@ -1145,19 +1156,20 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapperFilterer) ParseWrapperFulfillmentFailed } type GetConfig struct { - FallbackWeiPerUnitLink *big.Int - StalenessSeconds uint32 - FulfillmentFlatFeeLinkPPM uint32 - WrapperGasOverhead uint32 - CoordinatorGasOverhead uint32 - WrapperPremiumPercentage uint8 - KeyHash [32]byte - MaxNumWords uint8 + FallbackWeiPerUnitLink *big.Int + StalenessSeconds uint32 + FulfillmentFlatFeeLinkPPM uint32 + FulfillmentFlatFeeNativePPM uint32 + WrapperGasOverhead uint32 + CoordinatorGasOverhead uint32 + WrapperPremiumPercentage uint8 + KeyHash [32]byte + MaxNumWords uint8 } type SCallbacks struct { CallbackAddress common.Address CallbackGasLimit uint32 - RequestGasPrice *big.Int + RequestGasPrice uint64 } func (_VRFV2PlusWrapper *VRFV2PlusWrapper) ParseLog(log types.Log) (generated.AbigenLog, error) { @@ -1191,14 +1203,14 @@ func (_VRFV2PlusWrapper *VRFV2PlusWrapper) Address() common.Address { } type VRFV2PlusWrapperInterface interface { - COORDINATOR(opts *bind.CallOpts) (common.Address, error) - SUBSCRIPTIONID(opts *bind.CallOpts) (*big.Int, error) CalculateRequestPrice(opts *bind.CallOpts, _callbackGasLimit uint32) (*big.Int, error) CalculateRequestPriceNative(opts *bind.CallOpts, _callbackGasLimit uint32) (*big.Int, error) + CheckPaymentMode(opts *bind.CallOpts, extraArgs []byte, isLinkMode bool) error + EstimateRequestPrice(opts *bind.CallOpts, _callbackGasLimit uint32, _requestGasPriceWei *big.Int) (*big.Int, error) EstimateRequestPriceNative(opts *bind.CallOpts, _callbackGasLimit uint32, _requestGasPriceWei *big.Int) (*big.Int, error) @@ -1235,13 +1247,15 @@ type VRFV2PlusWrapperInterface interface { Enable(opts *bind.TransactOpts) (*types.Transaction, error) + Migrate(opts *bind.TransactOpts, newCoordinator common.Address) (*types.Transaction, error) + OnTokenTransfer(opts *bind.TransactOpts, _sender common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) - RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32) (*types.Transaction, error) + RequestRandomWordsInNative(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, extraArgs []byte) (*types.Transaction, error) - SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8) (*types.Transaction, error) + SetConfig(opts *bind.TransactOpts, _wrapperGasOverhead uint32, _coordinatorGasOverhead uint32, _wrapperPremiumPercentage uint8, _keyHash [32]byte, _maxNumWords uint8, _stalenessSeconds uint32, _fallbackWeiPerUnitLink *big.Int, _fulfillmentFlatFeeLinkPPM uint32, _fulfillmentFlatFeeNativePPM uint32) (*types.Transaction, error) SetCoordinator(opts *bind.TransactOpts, _vrfCoordinator common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go index ef1d4c30892..9cbd5ef964b 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example/vrfv2plus_wrapper_consumer_example.go @@ -31,8 +31,8 @@ var ( ) var VRFV2PlusWrapperConsumerExampleMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequestNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001650380380620016508339810160408190526200003491620001e2565b3380600084846001600160a01b038216156200006657600080546001600160a01b0319166001600160a01b0384161790555b600180546001600160a01b0319166001600160a01b03928316179055831615159050620000da5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b03848116919091179091558116156200010d576200010d8162000118565b50505050506200021a565b6001600160a01b038116331415620001735760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000d1565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001dd57600080fd5b919050565b60008060408385031215620001f657600080fd5b6200020183620001c5565b91506200021160208401620001c5565b90509250929050565b611426806200022a6000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c806384276d8111610081578063a168fa891161005b578063a168fa8914610185578063d8a4676f146101d7578063f2fde38b146101f957600080fd5b806384276d81146101375780638da5cb5b1461014a5780639c24ea401461017257600080fd5b80631fe543e3116100b25780631fe543e31461010757806379ba50971461011c5780637a8042bd1461012457600080fd5b80630c09b832146100ce5780631e1a3499146100f4575b600080fd5b6100e16100dc366004611281565b61020c565b6040519081526020015b60405180910390f35b6100e1610102366004611281565b6103d1565b61011a610115366004611192565b61051e565b005b61011a6105d7565b61011a610132366004611160565b6106d8565b61011a610145366004611160565b6107c2565b60025460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100eb565b61011a610180366004611101565b6108b2565b6101ba610193366004611160565b600460205260009081526040902080546001820154600390920154909160ff908116911683565b6040805193845291151560208401521515908201526060016100eb565b6101ea6101e5366004611160565b610949565b6040516100eb939291906113c9565b61011a610207366004611101565b610a6b565b6000610216610a7f565b610221848484610b02565b6001546040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8716600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690634306d3549060240160206040518083038186803b15801561029657600080fd5b505afa1580156102aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ce9190611179565b6040805160808101825282815260006020808301828152845183815280830186528486019081526060850184905288845260048352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055925180519495509193909261035a926002850192910190611088565b5060609190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560405181815282907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec49060200160405180910390a2509392505050565b60006103db610a7f565b6103e6848484610d07565b6001546040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff8716600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690634b1609359060240160206040518083038186803b15801561045b57600080fd5b505afa15801561046f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104939190611179565b604080516080810182528281526000602080830182815284518381528083018652848601908152600160608601819052898552600484529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169515159590951790945590518051949550919361035a9260028501920190611088565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105c9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f6e6c792056524620563220506c757320777261707065722063616e2066756c60448201527f66696c6c0000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6105d38282610e7a565b5050565b60035473ffffffffffffffffffffffffffffffffffffffff163314610658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105c0565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6106e0610a7f565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61071d60025473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b15801561078a57600080fd5b505af115801561079e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d3919061113e565b6107ca610a7f565b60006107eb60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610842576040519150601f19603f3d011682016040523d82523d6000602084013e610847565b606091505b50509050806105d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c6564000000000000000000000060448201526064016105c0565b60005473ffffffffffffffffffffffffffffffffffffffff1615610902576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008181526004602052604081205481906060906109c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e6400000000000000000000000000000060448201526064016105c0565b6000848152600460209081526040808320815160808101835281548152600182015460ff16151581850152600282018054845181870281018701865281815292959394860193830182828015610a3857602002820191906000526020600020905b815481526020019060010190808311610a24575b50505091835250506003919091015460ff1615156020918201528151908201516040909201519097919650945092505050565b610a73610a7f565b610a7c81610f91565b50565b60025473ffffffffffffffffffffffffffffffffffffffff163314610b00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105c0565b565b600080546001546040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8716600482015273ffffffffffffffffffffffffffffffffffffffff92831692634000aea09216908190634306d3549060240160206040518083038186803b158015610b7f57600080fd5b505afa158015610b93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb79190611179565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b8152600401610c0c93929190611308565b602060405180830381600087803b158015610c2657600080fd5b505af1158015610c3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5e919061113e565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b158015610cc757600080fd5b505afa158015610cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cff9190611179565b949350505050565b6001546040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600091829173ffffffffffffffffffffffffffffffffffffffff90911690634b1609359060240160206040518083038186803b158015610d7b57600080fd5b505afa158015610d8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db39190611179565b6001546040517f62a504fc00000000000000000000000000000000000000000000000000000000815263ffffffff808916600483015261ffff881660248301528616604482015291925073ffffffffffffffffffffffffffffffffffffffff16906362a504fc9083906064016020604051808303818588803b158015610e3857600080fd5b505af1158015610e4c573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610e719190611179565b95945050505050565b600082815260046020526040902054610eef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e6400000000000000000000000000000060448201526064016105c0565b6000828152600460209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558251610f4292600290920191840190611088565b50600082815260046020526040908190205490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610f8591859185916113a0565b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8116331415611011576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105c0565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b8280548282559060005260206000209081019282156110c3579160200282015b828111156110c35782518255916020019190600101906110a8565b506110cf9291506110d3565b5090565b5b808211156110cf57600081556001016110d4565b803563ffffffff811681146110fc57600080fd5b919050565b60006020828403121561111357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461113757600080fd5b9392505050565b60006020828403121561115057600080fd5b8151801515811461113757600080fd5b60006020828403121561117257600080fd5b5035919050565b60006020828403121561118b57600080fd5b5051919050565b600080604083850312156111a557600080fd5b8235915060208084013567ffffffffffffffff808211156111c557600080fd5b818601915086601f8301126111d957600080fd5b8135818111156111eb576111eb6113ea565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561122e5761122e6113ea565b604052828152858101935084860182860187018b101561124d57600080fd5b600095505b83861015611270578035855260019590950194938601938601611252565b508096505050505050509250929050565b60008060006060848603121561129657600080fd5b61129f846110e8565b9250602084013561ffff811681146112b657600080fd5b91506112c4604085016110e8565b90509250925092565b600081518084526020808501945080840160005b838110156112fd578151875295820195908201906001016112e1565b509495945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b818110156113585785810183015185820160800152820161133c565b8181111561136a576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b8381526060602082015260006113b960608301856112cd565b9050826040830152949350505050565b8381528215156020820152606060408201526000610e7160608301846112cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"}],\"name\":\"makeRequestNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b5060405162001743380380620017438339810160408190526200003491620001db565b3380600084846001600160a01b038216156200006657600080546001600160a01b0319166001600160a01b0384161790555b60601b6001600160601b031916608052506001600160a01b038216620000d35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200010657620001068162000111565b505050505062000213565b6001600160a01b0381163314156200016c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000ca565b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001d657600080fd5b919050565b60008060408385031215620001ef57600080fd5b620001fa83620001be565b91506200020a60208401620001be565b90509250929050565b60805160601c6114e76200025c600039600081816101c80152818161049701528181610b7001528181610c1201528181610cca01528181610dbf0152610e3d01526114e76000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80638da5cb5b1161008c578063a168fa8911610066578063a168fa89146101ea578063d8a4676f1461023c578063e76d51681461025e578063f2fde38b1461027c57600080fd5b80638da5cb5b146101715780639c24ea40146101b05780639ed0868d146101c357600080fd5b80631fe543e3116100c85780631fe543e31461012e57806379ba5097146101435780637a8042bd1461014b57806384276d811461015e57600080fd5b80630c09b832146100ef57806312065fe0146101155780631e1a34991461011b575b600080fd5b6101026100fd3660046112f4565b61028f565b6040519081526020015b60405180910390f35b47610102565b6101026101293660046112f4565b6103cc565b61014161013c366004611205565b610495565b005b610141610537565b6101416101593660046111d3565b610638565b61014161016c3660046111d3565b610726565b60015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010c565b6101416101be366004611174565b610816565b61018b7f000000000000000000000000000000000000000000000000000000000000000081565b61021f6101f83660046111d3565b600360208190526000918252604090912080546001820154919092015460ff918216911683565b60408051938452911515602084015215159082015260600161010c565b61024f61024a3660046111d3565b6108ad565b60405161010c9392919061144d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018b565b61014161028a366004611174565b6109cf565b60006102996109e3565b60006102b5604051806020016040528060001515815250610a66565b905060006102c586868685610b22565b6040805160808101825282815260006020808301828152845183815280830186528486019081526060850184905287845260038352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905592518051959850939550909390926103549260028501929101906110fb565b5060609190910151600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905560405181815283907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec49060200160405180910390a250509392505050565b60006103d66109e3565b60006103f2604051806020016040528060011515815250610a66565b9050600061040286868685610d71565b604080516080810182528281526000602080830182815284518381528083018652848601908152600160608601819052888552600384529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001695151595909517909455905180519598509395509093919261035492600285019291909101906110fb565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610528576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6105328383610eed565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146105b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161051f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560028054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6106406109e3565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61067d60015473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b1580156106ea57600080fd5b505af11580156106fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072291906111b1565b5050565b61072e6109e3565b600061074f60015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146107a6576040519150601f19603f3d011682016040523d82523d6000602084013e6107ab565b606091505b5050905080610722576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c65640000000000000000000000604482015260640161051f565b60005473ffffffffffffffffffffffffffffffffffffffff1615610866576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000818152600360205260408120548190606090610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161051f565b6000848152600360209081526040808320815160808101835281548152600182015460ff1615158185015260028201805484518187028101870186528181529295939486019383018282801561099c57602002820191906000526020600020905b815481526020019060010190808311610988575b50505091835250506003919091015460ff1615156020918201528151908201516040909201519097919650945092505050565b6109d76109e3565b6109e081611004565b50565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161051f565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401610a9f91511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b158015610bb257600080fd5b505afa158015610bc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bea91906111ec565b60005460405191925073ffffffffffffffffffffffffffffffffffffffff1690634000aea0907f0000000000000000000000000000000000000000000000000000000000000000908490610c48908b908b908b908b9060200161146e565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610c75939291906113e6565b602060405180830381600087803b158015610c8f57600080fd5b505af1158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc791906111b1565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b158015610d2e57600080fd5b505afa158015610d42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6691906111ec565b915094509492505050565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b1609359060240160206040518083038186803b158015610e0157600080fd5b505afa158015610e15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3991906111ec565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b8152600401610e9b949392919061146e565b6020604051808303818588803b158015610eb457600080fd5b505af1158015610ec8573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d6691906111ec565b600082815260036020526040902054610f62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e64000000000000000000000000000000604482015260640161051f565b6000828152600360209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558251610fb5926002909201918401906110fb565b50600082815260036020526040908190205490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610ff89185918591611424565b60405180910390a15050565b73ffffffffffffffffffffffffffffffffffffffff8116331415611084576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161051f565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b828054828255906000526020600020908101928215611136579160200282015b8281111561113657825182559160200191906001019061111b565b50611142929150611146565b5090565b5b808211156111425760008155600101611147565b803563ffffffff8116811461116f57600080fd5b919050565b60006020828403121561118657600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146111aa57600080fd5b9392505050565b6000602082840312156111c357600080fd5b815180151581146111aa57600080fd5b6000602082840312156111e557600080fd5b5035919050565b6000602082840312156111fe57600080fd5b5051919050565b6000806040838503121561121857600080fd5b8235915060208084013567ffffffffffffffff8082111561123857600080fd5b818601915086601f83011261124c57600080fd5b81358181111561125e5761125e6114ab565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156112a1576112a16114ab565b604052828152858101935084860182860187018b10156112c057600080fd5b600095505b838610156112e35780358552600195909501949386019386016112c5565b508096505050505050509250929050565b60008060006060848603121561130957600080fd5b6113128461115b565b9250602084013561ffff8116811461132957600080fd5b91506113376040850161115b565b90509250925092565b600081518084526020808501945080840160005b8381101561137057815187529582019590820190600101611354565b509495945050505050565b6000815180845260005b818110156113a157602081850181015186830182015201611385565b818111156113b3576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8416815282602082015260606040820152600061141b606083018461137b565b95945050505050565b83815260606020820152600061143d6060830185611340565b9050826040830152949350505050565b838152821515602082015260606040820152600061141b6060830184611340565b600063ffffffff808716835261ffff86166020840152808516604084015250608060608301526114a1608083018461137b565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusWrapperConsumerExampleABI = VRFV2PlusWrapperConsumerExampleMetaData.ABI @@ -171,6 +171,50 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleTransacto return _VRFV2PlusWrapperConsumerExample.Contract.contract.Transact(opts, method, params...) } +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCaller) GetBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2PlusWrapperConsumerExample.contract.Call(opts, &out, "getBalance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleSession) GetBalance() (*big.Int, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.GetBalance(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCallerSession) GetBalance() (*big.Int, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.GetBalance(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCaller) GetLinkToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2PlusWrapperConsumerExample.contract.Call(opts, &out, "getLinkToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleSession) GetLinkToken() (common.Address, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.GetLinkToken(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCallerSession) GetLinkToken() (common.Address, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.GetLinkToken(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -202,6 +246,28 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCallerSes return _VRFV2PlusWrapperConsumerExample.Contract.GetRequestStatus(&_VRFV2PlusWrapperConsumerExample.CallOpts, _requestId) } +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCaller) IVrfV2PlusWrapper(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2PlusWrapperConsumerExample.contract.Call(opts, &out, "i_vrfV2PlusWrapper") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleSession) IVrfV2PlusWrapper() (common.Address, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.IVrfV2PlusWrapper(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + +func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCallerSession) IVrfV2PlusWrapper() (common.Address, error) { + return _VRFV2PlusWrapperConsumerExample.Contract.IVrfV2PlusWrapper(&_VRFV2PlusWrapperConsumerExample.CallOpts) +} + func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExampleCaller) Owner(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _VRFV2PlusWrapperConsumerExample.contract.Call(opts, &out, "owner") @@ -918,10 +984,16 @@ func (_VRFV2PlusWrapperConsumerExample *VRFV2PlusWrapperConsumerExample) Address } type VRFV2PlusWrapperConsumerExampleInterface interface { + GetBalance(opts *bind.CallOpts) (*big.Int, error) + + GetLinkToken(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) + IVrfV2PlusWrapper(opts *bind.CallOpts) (common.Address, error) + Owner(opts *bind.CallOpts) (common.Address, error) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, diff --git a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go index d8c85370649..231945c9b7a 100644 --- a/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go +++ b/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer/vrfv2plus_wrapper_load_test_consumer.go @@ -31,8 +31,8 @@ var ( ) var VRFV2PlusWrapperLoadTestConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2PlusWrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrapper\",\"outputs\":[{\"internalType\":\"contractVRFV2PlusWrapperInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequestsNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x6080604052600060065560006007556103e76008553480156200002157600080fd5b5060405162001dd138038062001dd18339810160408190526200004491620001f2565b3380600084846001600160a01b038216156200007657600080546001600160a01b0319166001600160a01b0384161790555b600180546001600160a01b0319166001600160a01b03928316179055831615159050620000ea5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b03848116919091179091558116156200011d576200011d8162000128565b50505050506200022a565b6001600160a01b038116331415620001835760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000e1565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001ed57600080fd5b919050565b600080604083850312156200020657600080fd5b6200021183620001d5565b91506200022160208401620001d5565b90509250929050565b611b97806200023a6000396000f3fe6080604052600436106101635760003560e01c80638f6b7070116100c0578063d826f88f11610074578063dc1670db11610059578063dc1670db14610421578063f176596214610437578063f2fde38b1461045757600080fd5b8063d826f88f146103c2578063d8a4676f146103ee57600080fd5b8063a168fa89116100a5578063a168fa89146102f7578063afacbf9c1461038c578063b1e21749146103ac57600080fd5b80638f6b7070146102ac5780639c24ea40146102d757600080fd5b806374dba124116101175780637a8042bd116100fc5780637a8042bd1461022057806384276d81146102405780638da5cb5b1461026057600080fd5b806374dba124146101f557806379ba50971461020b57600080fd5b80631fe543e3116101485780631fe543e3146101a7578063557d2e92146101c9578063737144bc146101df57600080fd5b806312065fe01461016f5780631757f11c1461019157600080fd5b3661016a57005b600080fd5b34801561017b57600080fd5b50475b6040519081526020015b60405180910390f35b34801561019d57600080fd5b5061017e60075481565b3480156101b357600080fd5b506101c76101c23660046117a4565b610477565b005b3480156101d557600080fd5b5061017e60055481565b3480156101eb57600080fd5b5061017e60065481565b34801561020157600080fd5b5061017e60085481565b34801561021757600080fd5b506101c7610530565b34801561022c57600080fd5b506101c761023b366004611772565b610631565b34801561024c57600080fd5b506101c761025b366004611772565b61071b565b34801561026c57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610188565b3480156102b857600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff16610287565b3480156102e357600080fd5b506101c76102f2366004611713565b61080b565b34801561030357600080fd5b50610355610312366004611772565b600b602052600090815260409020805460018201546003830154600484015460058501546006860154600790960154949560ff9485169593949293919290911687565b604080519788529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e001610188565b34801561039857600080fd5b506101c76103a7366004611893565b6108a2565b3480156103b857600080fd5b5061017e60095481565b3480156103ce57600080fd5b506101c76000600681905560078190556103e76008556005819055600455565b3480156103fa57600080fd5b5061040e610409366004611772565b610b12565b60405161018897969594939291906119e3565b34801561042d57600080fd5b5061017e60045481565b34801561044357600080fd5b506101c7610452366004611893565b610c95565b34801561046357600080fd5b506101c7610472366004611713565b610efd565b60015473ffffffffffffffffffffffffffffffffffffffff163314610522576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f6e6c792056524620563220506c757320777261707065722063616e2066756c60448201527f66696c6c0000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61052c8282610f11565b5050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146105b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610519565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6106396110f0565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61067660025473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b1580156106e357600080fd5b505af11580156106f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052c9190611750565b6107236110f0565b600061074460025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461079b576040519150601f19603f3d011682016040523d82523d6000602084013e6107a0565b606091505b505090508061052c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c656400000000000000000000006044820152606401610519565b60005473ffffffffffffffffffffffffffffffffffffffff161561085b576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6108aa6110f0565b60005b8161ffff168161ffff161015610b0b5760006108ca868686611173565b6009819055905060006108db611378565b6001546040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8a16600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690634306d3549060240160206040518083038186803b15801561095057600080fd5b505afa158015610964573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610988919061178b565b604080516101008101825282815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850189905260c0850184905260e08501849052898452600b8352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790559251805194955091939092610a30926002850192910190611688565b50606082015160038201556080820151600482015560a082015160058083019190915560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610aa383611af3565b90915550506000838152600a6020526040908190208390555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610aed9084815260200190565b60405180910390a25050508080610b0390611ad1565b9150506108ad565b5050505050565b6000818152600b602052604081205481906060908290819081908190610b94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610519565b6000888152600b6020908152604080832081516101008101835281548152600182015460ff16151581850152600282018054845181870281018701865281815292959394860193830182828015610c0a57602002820191906000526020600020905b815481526020019060010190808311610bf6575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff1615151515815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610c9d6110f0565b60005b8161ffff168161ffff161015610b0b576000610cbd86868661141e565b600981905590506000610cce611378565b6001546040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff8a16600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690634b1609359060240160206040518083038186803b158015610d4357600080fd5b505afa158015610d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7b919061178b565b604080516101008101825282815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850189905260c08501849052600160e086018190528a8552600b84529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001695151595909517909455905180519495509193610e229260028501920190611688565b50606082015160038201556080820151600482015560a082015160058083019190915560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610e9583611af3565b90915550506000838152600a6020526040908190208390555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610edf9084815260200190565b60405180910390a25050508080610ef590611ad1565b915050610ca0565b610f056110f0565b610f0e81611591565b50565b6000828152600b6020526040902054610f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610519565b6000610f90611378565b6000848152600a602052604081205491925090610fad9083611aba565b90506000610fbe82620f4240611a7d565b9050600754821115610fd05760078290555b6008548210610fe157600854610fe3565b815b600855600454610ff35780611026565b600454611001906001611a2a565b816004546006546110129190611a7d565b61101c9190611a2a565b6110269190611a42565b6006556004805490600061103983611af3565b90915550506000858152600b60209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055855161109192600290920191870190611688565b506000858152600b602052604090819020426004820155600681018590555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b916110e191889188916119ba565b60405180910390a15050505050565b60025473ffffffffffffffffffffffffffffffffffffffff163314611171576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610519565b565b600080546001546040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8716600482015273ffffffffffffffffffffffffffffffffffffffff92831692634000aea09216908190634306d3549060240160206040518083038186803b1580156111f057600080fd5b505afa158015611204573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611228919061178b565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b815260040161127d93929190611922565b602060405180830381600087803b15801561129757600080fd5b505af11580156112ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cf9190611750565b50600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561133857600080fd5b505afa15801561134c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611370919061178b565b949350505050565b60004661a4b181148061138d575062066eed81145b1561141757606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113d957600080fd5b505afa1580156113ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611411919061178b565b91505090565b4391505090565b6001546040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600091829173ffffffffffffffffffffffffffffffffffffffff90911690634b1609359060240160206040518083038186803b15801561149257600080fd5b505afa1580156114a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ca919061178b565b6001546040517f62a504fc00000000000000000000000000000000000000000000000000000000815263ffffffff808916600483015261ffff881660248301528616604482015291925073ffffffffffffffffffffffffffffffffffffffff16906362a504fc9083906064016020604051808303818588803b15801561154f57600080fd5b505af1158015611563573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611588919061178b565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff8116331415611611576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610519565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b8280548282559060005260206000209081019282156116c3579160200282015b828111156116c35782518255916020019190600101906116a8565b506116cf9291506116d3565b5090565b5b808211156116cf57600081556001016116d4565b803561ffff811681146116fa57600080fd5b919050565b803563ffffffff811681146116fa57600080fd5b60006020828403121561172557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461174957600080fd5b9392505050565b60006020828403121561176257600080fd5b8151801515811461174957600080fd5b60006020828403121561178457600080fd5b5035919050565b60006020828403121561179d57600080fd5b5051919050565b600080604083850312156117b757600080fd5b8235915060208084013567ffffffffffffffff808211156117d757600080fd5b818601915086601f8301126117eb57600080fd5b8135818111156117fd576117fd611b5b565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561184057611840611b5b565b604052828152858101935084860182860187018b101561185f57600080fd5b600095505b83861015611882578035855260019590950194938601938601611864565b508096505050505050509250929050565b600080600080608085870312156118a957600080fd5b6118b2856116ff565b93506118c0602086016116e8565b92506118ce604086016116ff565b91506118dc606086016116e8565b905092959194509250565b600081518084526020808501945080840160005b83811015611917578151875295820195908201906001016118fb565b509495945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b8181101561197257858101830151858201608001528201611956565b81811115611984576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b8381526060602082015260006119d360608301856118e7565b9050826040830152949350505050565b878152861515602082015260e060408201526000611a0460e08301886118e7565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b60008219821115611a3d57611a3d611b2c565b500190565b600082611a78577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611ab557611ab5611b2c565b500290565b600082821015611acc57611acc611b2c565b500390565b600061ffff80831681811415611ae957611ae9611b2c565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611b2557611b25611b2c565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2PlusWrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"LINKAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyVRFWrapperCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkToken\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2PlusWrapper\",\"outputs\":[{\"internalType\":\"contractIVRFV2PlusWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequestsNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"_randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"native\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"setLinkToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b5060405162001e9838038062001e988339810160408190526200004491620001eb565b3380600084846001600160a01b038216156200007657600080546001600160a01b0319166001600160a01b0384161790555b60601b6001600160601b031916608052506001600160a01b038216620000e35760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200011657620001168162000121565b505050505062000223565b6001600160a01b0381163314156200017c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000da565b600280546001600160a01b0319166001600160a01b03838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001e657600080fd5b919050565b60008060408385031215620001ff57600080fd5b6200020a83620001ce565b91506200021a60208401620001ce565b90509250929050565b60805160601c611c2c6200026c600039600081816102e9015281816104b80152818161119701528181611239015281816112f10152818161148301526115010152611c2c6000f3fe60806040526004361061016e5760003560e01c80639c24ea40116100cb578063d826f88f1161007f578063e76d516811610059578063e76d51681461044b578063f176596214610476578063f2fde38b1461049657600080fd5b8063d826f88f146103d6578063d8a4676f14610402578063dc1670db1461043557600080fd5b8063a168fa89116100b0578063a168fa891461030b578063afacbf9c146103a0578063b1e21749146103c057600080fd5b80639c24ea40146102b75780639ed0868d146102d757600080fd5b806374dba124116101225780637a8042bd116101075780637a8042bd1461022b57806384276d811461024b5780638da5cb5b1461026b57600080fd5b806374dba1241461020057806379ba50971461021657600080fd5b80631fe543e3116101535780631fe543e3146101b2578063557d2e92146101d4578063737144bc146101ea57600080fd5b806312065fe01461017a5780631757f11c1461019c57600080fd5b3661017557005b600080fd5b34801561018657600080fd5b50475b6040519081526020015b60405180910390f35b3480156101a857600080fd5b5061018960065481565b3480156101be57600080fd5b506101d26101cd3660046117eb565b6104b6565b005b3480156101e057600080fd5b5061018960045481565b3480156101f657600080fd5b5061018960055481565b34801561020c57600080fd5b5061018960075481565b34801561022257600080fd5b506101d2610558565b34801561023757600080fd5b506101d26102463660046117b9565b610659565b34801561025757600080fd5b506101d26102663660046117b9565b610747565b34801561027757600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610193565b3480156102c357600080fd5b506101d26102d236600461175a565b610837565b3480156102e357600080fd5b506102927f000000000000000000000000000000000000000000000000000000000000000081565b34801561031757600080fd5b506103696103263660046117b9565b600a602052600090815260409020805460018201546003830154600484015460058501546006860154600790960154949560ff9485169593949293919290911687565b604080519788529515156020880152948601939093526060850191909152608084015260a0830152151560c082015260e001610193565b3480156103ac57600080fd5b506101d26103bb3660046118da565b6108ce565b3480156103cc57600080fd5b5061018960085481565b3480156103e257600080fd5b506101d26000600581905560068190556103e76007556004819055600355565b34801561040e57600080fd5b5061042261041d3660046117b9565b610ab5565b6040516101939796959493929190611a3b565b34801561044157600080fd5b5061018960035481565b34801561045757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610292565b34801561048257600080fd5b506101d26104913660046118da565b610c38565b3480156104a257600080fd5b506101d26104b136600461175a565b610e17565b7f00000000000000000000000000000000000000000000000000000000000000003373ffffffffffffffffffffffffffffffffffffffff821614610549576040517f8ba9316e00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff821660248201526044015b60405180910390fd5b6105538383610e2b565b505050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146105d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610540565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560028054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b61066161100a565b60005473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb61069e60015473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b15801561070b57600080fd5b505af115801561071f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107439190611797565b5050565b61074f61100a565b600061077060015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146107c7576040519150601f19603f3d011682016040523d82523d6000602084013e6107cc565b606091505b5050905080610743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f77697468647261774e6174697665206661696c656400000000000000000000006044820152606401610540565b60005473ffffffffffffffffffffffffffffffffffffffff1615610887576040517f64f778ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6108d661100a565b60005b8161ffff168161ffff161015610aae57600061090560405180602001604052806000151581525061108d565b905060008061091688888886611149565b60088290559092509050600061092a611398565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c0850184905260e08501849052898452600a8352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905592518051949550919390926109d29260028501929101906116cf565b5060608201516003820155608082015160048083019190915560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610a4583611b88565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610a8f9085815260200190565b60405180910390a2505050508080610aa690611b66565b9150506108d9565b5050505050565b6000818152600a602052604081205481906060908290819081908190610b37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610540565b6000888152600a6020908152604080832081516101008101835281548152600182015460ff16151581850152600282018054845181870281018701865281815292959394860193830182828015610bad57602002820191906000526020600020905b815481526020019060010190808311610b99575b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682015481526020016007820160009054906101000a900460ff1615151515815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610c4061100a565b60005b8161ffff168161ffff161015610aae576000610c6f60405180602001604052806001151581525061108d565b9050600080610c8088888886611435565b600882905590925090506000610c94611398565b604080516101008101825284815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850187905260c08501849052600160e086018190528a8552600a84529590932084518155905194810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001695151595909517909455905180519495509193610d3b92600285019201906116cf565b5060608201516003820155608082015160048083019190915560a0830151600583015560c0830151600683015560e090920151600790910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558054906000610dae83611b88565b9091555050600083815260096020526040908190208290555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec490610df89085815260200190565b60405180910390a2505050508080610e0f90611b66565b915050610c43565b610e1f61100a565b610e28816115b1565b50565b6000828152600a6020526040902054610ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610540565b6000610eaa611398565b60008481526009602052604081205491925090610ec79083611b4f565b90506000610ed882620f4240611b12565b9050600654821115610eea5760068290555b6007548210610efb57600754610efd565b815b600755600354610f0d5780610f40565b600354610f1b906001611abf565b81600354600554610f2c9190611b12565b610f369190611abf565b610f409190611ad7565b60055560038054906000610f5383611b88565b90915550506000858152600a60209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558551610fab926002909201918701906116cf565b506000858152600a602052604090819020426004820155600681018590555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610ffb9188918891611a12565b60405180910390a15050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461108b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610540565b565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa826040516024016110c691511515815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b1580156111d957600080fd5b505afa1580156111ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121191906117d2565b60005460405191925073ffffffffffffffffffffffffffffffffffffffff1690634000aea0907f000000000000000000000000000000000000000000000000000000000000000090849061126f908b908b908b908b90602001611a82565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161129c939291906119d4565b602060405180830381600087803b1580156112b657600080fd5b505af11580156112ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ee9190611797565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b15801561135557600080fd5b505afa158015611369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138d91906117d2565b915094509492505050565b6000466113a4816116a8565b1561142e57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113f057600080fd5b505afa158015611404573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142891906117d2565b91505090565b4391505090565b6040517f4b16093500000000000000000000000000000000000000000000000000000000815263ffffffff85166004820152600090819073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634b1609359060240160206040518083038186803b1580156114c557600080fd5b505afa1580156114d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fd91906117d2565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639cfc058e82888888886040518663ffffffff1660e01b815260040161155f9493929190611a82565b6020604051808303818588803b15801561157857600080fd5b505af115801561158c573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061138d91906117d2565b73ffffffffffffffffffffffffffffffffffffffff8116331415611631576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610540565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600154604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600061a4b18214806116bc575062066eed82145b806116c9575062066eee82145b92915050565b82805482825590600052602060002090810192821561170a579160200282015b8281111561170a5782518255916020019190600101906116ef565b5061171692915061171a565b5090565b5b80821115611716576000815560010161171b565b803561ffff8116811461174157600080fd5b919050565b803563ffffffff8116811461174157600080fd5b60006020828403121561176c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461179057600080fd5b9392505050565b6000602082840312156117a957600080fd5b8151801515811461179057600080fd5b6000602082840312156117cb57600080fd5b5035919050565b6000602082840312156117e457600080fd5b5051919050565b600080604083850312156117fe57600080fd5b8235915060208084013567ffffffffffffffff8082111561181e57600080fd5b818601915086601f83011261183257600080fd5b81358181111561184457611844611bf0565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561188757611887611bf0565b604052828152858101935084860182860187018b10156118a657600080fd5b600095505b838610156118c95780358552600195909501949386019386016118ab565b508096505050505050509250929050565b600080600080608085870312156118f057600080fd5b6118f985611746565b93506119076020860161172f565b925061191560408601611746565b91506119236060860161172f565b905092959194509250565b600081518084526020808501945080840160005b8381101561195e57815187529582019590820190600101611942565b509495945050505050565b6000815180845260005b8181101561198f57602081850181015186830182015201611973565b818111156119a1576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611a096060830184611969565b95945050505050565b838152606060208201526000611a2b606083018561192e565b9050826040830152949350505050565b878152861515602082015260e060408201526000611a5c60e083018861192e565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b600063ffffffff808716835261ffff8616602084015280851660408401525060806060830152611ab56080830184611969565b9695505050505050565b60008219821115611ad257611ad2611bc1565b500190565b600082611b0d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b4a57611b4a611bc1565b500290565b600082821015611b6157611b61611bc1565b500390565b600061ffff80831681811415611b7e57611b7e611bc1565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611bba57611bba611bc1565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2PlusWrapperLoadTestConsumerABI = VRFV2PlusWrapperLoadTestConsumerMetaData.ABI @@ -193,6 +193,28 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerS return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetBalance(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) } +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) GetLinkToken(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "getLinkToken") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) GetLinkToken() (common.Address, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetLinkToken(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerSession) GetLinkToken() (common.Address, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetLinkToken(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) +} + func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -228,9 +250,9 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerS return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetRequestStatus(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts, _requestId) } -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) GetWrapper(opts *bind.CallOpts) (common.Address, error) { +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) IVrfV2PlusWrapper(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "getWrapper") + err := _VRFV2PlusWrapperLoadTestConsumer.contract.Call(opts, &out, "i_vrfV2PlusWrapper") if err != nil { return *new(common.Address), err @@ -242,12 +264,12 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) } -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) GetWrapper() (common.Address, error) { - return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetWrapper(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerSession) IVrfV2PlusWrapper() (common.Address, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.IVrfV2PlusWrapper(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) } -func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerSession) GetWrapper() (common.Address, error) { - return _VRFV2PlusWrapperLoadTestConsumer.Contract.GetWrapper(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) +func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCallerSession) IVrfV2PlusWrapper() (common.Address, error) { + return _VRFV2PlusWrapperLoadTestConsumer.Contract.IVrfV2PlusWrapper(&_VRFV2PlusWrapperLoadTestConsumer.CallOpts) } func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { @@ -1136,11 +1158,13 @@ func (_VRFV2PlusWrapperLoadTestConsumer *VRFV2PlusWrapperLoadTestConsumer) Addre type VRFV2PlusWrapperLoadTestConsumerInterface interface { GetBalance(opts *bind.CallOpts) (*big.Int, error) + GetLinkToken(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) - GetWrapper(opts *bind.CallOpts) (common.Address, error) + IVrfV2PlusWrapper(opts *bind.CallOpts) (common.Address, error) Owner(opts *bind.CallOpts) (common.Address, error) diff --git a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt index da24539bf05..0d0bb388f2f 100644 --- a/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,20 +1,26 @@ GETH_VERSION: 1.12.0 +KeeperConsumer: ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 +KeeperConsumerPerformance: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 +PerformDataChecker: ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 +UpkeepCounter: ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 +UpkeepPerformCounterRestrictive: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c +VRFv2Consumer: ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab -authorized_forwarder: ../../contracts/solc/v0.7/AuthorizedForwarder.abi ../../contracts/solc/v0.7/AuthorizedForwarder.bin 426d0866a294c77b27a526265f98c688326eb3dec3b7a698180c5f1921ebdf56 -authorized_receiver: ../../contracts/solc/v0.7/AuthorizedReceiver.abi ../../contracts/solc/v0.7/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f +authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 +authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f automation_consumer_benchmark: ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.abi ../../contracts/solc/v0.8.16/AutomationConsumerBenchmark.bin f52c76f1aaed4be541d82d97189d70f5aa027fc9838037dd7a7d21910c8c488e automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic.bin 15ae0c367297955fdab4b552dbb10e1f2be80a8fde0efec4a4d398693e9d72b5 automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42 automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa -batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin c5ab26709a01050402615659403f32d5cd1b85f3ad6bb6bfe021692f4233cf19 +batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 -blockhash_store: ../../contracts/solc/v0.6/BlockhashStore.abi ../../contracts/solc/v0.6/BlockhashStore.bin a0dc60bcc4bf071033d23fddf7ae936c6a4d1dd81488434b7e24b7aa1fabc37c +blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e +chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 consumer_wrapper: ../../contracts/solc/v0.7/Consumer.abi ../../contracts/solc/v0.7/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 cron_upkeep_wrapper: ../../contracts/solc/v0.8.6/CronUpkeep.abi - 362fcfcf30a6ab3acff83095ea4b2b9056dd5e9dcb94bc5411aae58995d22709 -derived_price_feed_wrapper: ../../contracts/solc/v0.8.6/DerivedPriceFeed.abi ../../contracts/solc/v0.8.6/DerivedPriceFeed.bin c8542e6c850c2d0fffb79a7f7213dc927ec64e6ddd54e1224cb2fb4a13aabdd0 dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol.bin 583a448170b13abf7ed64e406e8177d78c9e55ab44efd141eee60de23a71ee3b flags_wrapper: ../../contracts/solc/v0.6/Flags.abi ../../contracts/solc/v0.6/Flags.bin 2034d1b562ca37a63068851915e3703980276e8d5f7db6db8a3351a49d69fc4a flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator.abi ../../contracts/solc/v0.6/FluxAggregator.bin a3b0a6396c4aa3b5ee39b3c4bd45efc89789d4859379a8a92caca3a0496c5794 @@ -22,33 +28,36 @@ functions_billing_registry_events_mock: ../../contracts/solc/v0.8.6/FunctionsBil functions_oracle_events_mock: ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723 gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8 -i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.bin 4426a320baaef8a66692699ec008e371eb7f841b1f9f02ff817c0eee0c63c7b5 +i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e +keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 +keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin 53d7902867ce421641ffa9de63204b89ab9dc157b93f0beb9ac08c6450365a70 keeper_registrar_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistrar.abi ../../contracts/solc/v0.8.6/KeeperRegistrar.bin e49b2f8b23da17af1ed2209b8ae0968cc04350554d636711e6c24a3ad3118692 keeper_registrar_wrapper1_2_mock: ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistrar1_2Mock.bin 5b155a7cb3def309fd7525de1d7cd364ebf8491bdc3060eac08ea0ff55ab29bc keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistrar2_0.bin 647f125c2f0dafabcdc545cb77b15dc2ec3ea9429357806813179b1fd555c2d2 -keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.bin 0176d7abdb01b370c5bf4f670d9abf85ca10aff53b1f7bdad41f85fabe666020 +keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1.bin 467d10741a04601b136553a2b1c6ab37f2a65d809366faf03180a22ff26be215 keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df -keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2.bin c08f903e7ecbdf89bbfea32c6dd334d3bf908ac809ebf63545890798a5f7a4a7 -keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3.bin 5e1414eacbc1880b7349a4f253b7eca176f7f6300ef3cd834c493ce795a17e25 +keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2.bin a40ff877dd7c280f984cbbb2b428e160662b0c295e881d5f778f941c0088ca22 +keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 log_emitter: ../../contracts/solc/v0.8.19/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter.bin 244ba13730c036de0b02beef4e3d9c9a96946ce353c27f366baecc7f5be5a6fd -log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin dfe5f8800251b464cd13f7ef966698ab7f0d8f6a5387520f09b602cfbf48f123 +log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter.bin 42426bbb83f96dfbe55fc576d6c65020eaeed690e2289cf99b0c4aa810a5f4ec mock_aggregator_proxy: ../../contracts/solc/v0.8.6/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy.bin b16c108f3dd384c342ddff5e94da7c0a8d39d1be5e3d8f2cf61ecc7f0e50ff42 mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator.bin 1c52c24f797b8482aa12b8251dcea1c072827bd5b3426b822621261944b99ca0 mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba offchain_aggregator_wrapper: OffchainAggregator/OffchainAggregator.abi - 5c8d6562e94166d4790f1ee6e4321d359d9f7262e6c5452a712b1f1c896f45cf -operator_factory: ../../contracts/solc/v0.7/OperatorFactory.abi ../../contracts/solc/v0.7/OperatorFactory.bin 0bbac9ac2e45f988b8365a83a36dff97534c14d315ebe5a1fc725d87f00c15d5 -operator_wrapper: ../../contracts/solc/v0.7/Operator.abi ../../contracts/solc/v0.7/Operator.bin 45036dc5046de66ba03f57b48ef8b629700e863af388cb509b2fa259989762e8 +operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory.bin 0fdfacf8879537b854875608dfca41c6221c342174417112acaa67dfcadafddc +operator_wrapper: ../../contracts/solc/v0.8.19/Operator.abi ../../contracts/solc/v0.8.19/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 oracle_wrapper: ../../contracts/solc/v0.6/Oracle.abi ../../contracts/solc/v0.6/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a +perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 @@ -60,10 +69,10 @@ solidity_vrf_wrapper: ../../contracts/solc/v0.6/VRF.abi ../../contracts/solc/v0. streams_lookup_compatible_interface: ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.abi ../../contracts/solc/v0.8.16/StreamsLookupCompatibleInterface.bin feb92cc666df21ea04ab9d7a588a513847b01b2f66fc167d06ab28ef2b17e015 streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/StreamsLookupUpkeep.bin b1a598963cacac51ed4706538d0f142bdc0d94b9a4b13e2d402131cdf05c9bcf test_api_consumer_wrapper: ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin ed10893cb18894c18e275302329c955f14ea2de37ee044f84aa1e067ac5ea71e -trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin 34e71c5dc94f50e21f2bef76b0daa5821634655ca3722ce1204ce43cca1b2e19 +trusted_blockhash_store: ../../contracts/solc/v0.8.6/TrustedBlockhashStore.abi ../../contracts/solc/v0.8.6/TrustedBlockhashStore.bin 98cb0dc06c15af5dcd3b53bdfc98e7ed2489edc96a42203294ac2fc0efdda02b type_and_version_interface_wrapper: ../../contracts/solc/v0.8.6/TypeAndVersionInterface.abi ../../contracts/solc/v0.8.6/TypeAndVersionInterface.bin bc9c3a6e73e3ebd5b58754df0deeb3b33f4bb404d5709bb904aed51d32f4b45e -upkeep_counter_wrapper: ../../contracts/solc/v0.7/UpkeepCounter.abi ../../contracts/solc/v0.7/UpkeepCounter.bin 901961ebf18906febc1c350f02da85c7ea1c2a68da70cfd94efa27c837a48663 -upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.7/UpkeepPerformCounterRestrictive.bin 8975a058fba528e16d8414dc6f13946d17a145fcbc66cf25a32449b6fe1ce878 +upkeep_counter_wrapper: ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin 77f000229a501f638dd2dc439859257f632894c728b31e68aea4f6d6c52f1b71 +upkeep_perform_counter_restrictive_wrapper: ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin 20955b21acceb58355fa287b29194a73edf5937067ba7140667301017cb2b24c upkeep_transcoder: ../../contracts/solc/v0.8.6/UpkeepTranscoder.abi ../../contracts/solc/v0.8.6/UpkeepTranscoder.bin 336c92a981597be26508455f81a908a0784a817b129a59686c5b2c4afcba730a verifiable_load_log_trigger_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadLogTriggerUpkeep.bin fb674ba44c0e8f3b385cd10b2f7dea5cd07b5f38df08066747e8b1542e152557 verifiable_load_streams_lookup_upkeep_wrapper: ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.abi ../../contracts/solc/v0.8.16/VerifiableLoadStreamsLookupUpkeep.bin 785f68c44bfff070505eaa65e38a1af94046e5f9afc1189bcf2c8cfcd1102d66 @@ -72,35 +81,36 @@ vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/s vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 -vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 906e8155db28513c64c6f828d5b8eaf586b873de4369c77c0a19b6c5adf623c1 -vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.bin b3b2ed681837264ec3f180d180ef6fb4d6f4f89136673268b57d540b0d682618 +vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 +vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5.bin b0e7c42a30b36d9d31fa9a3f26bad7937152e3dddee5bd8dd3d121390c879ab6 vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus.bin e4409bbe361258273458a5c99408b3d7f0cc57a2560dee91c0596cc6d6f738be vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal.bin 834a2ce0e83276372a0e1446593fd89798f4cf6dc95d4be0113e99fadf61558b vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c -vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.bin 6c8f08fe8ae9254ae0607dffa5faf2d554488850aa788795b0445938488ad9ce +vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 -vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.bin f8d8cd2a9287f7f98541027cfdddeea209c5a17184ee37204181c97897a52c41 +vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb -vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.bin 9a53f1f6d23f6f9bd9781284d8406e4b0741d59d13da2bdf4a9e0a8754c88101 +vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.bin 0537bbe96c5a8bbd44d0a65fbb7e51f6a9f9e75f4673225845ac1ba33f4e7974 vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece -vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.bin 41a6c14753817ef6143716082754a30653a36b1902b596f695afc1b56940c0ae -vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.bin e2aa4cfef91b1d1869ec1f517b4d41049884e0e25345384c2fccbe08cda3e603 -vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.bin 8bc4a8b74d302b9a7a37556d3746105f487c4d3555643721748533d01b1ae5a4 -vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.bin 24850318f2af4ad0fab64bc42f0d815bc41388902eba190720e33e4c11f2f0b9 -vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.bin 30b6d1af9c4ae05daddda2afdab1877d857ab5321afe3540a01e94d5ded9bcef +vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 +vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics.bin 0a89cb7ed9dfb42f91e559b03dc351ccdbe14d281a7ab71c63bd3f47eeed7711 +vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample.bin 6226d05afa1664033b182bfbdde11d5dfb1d4c8e3eb0bd0448c8bfb76f5b96e4 +vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample.bin 7541f986571b8a5671a256edc27ae9b8df9bcdff45ac3b96e5609bbfcc320e4e +vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion.bin c0793d86fb6e45342c4424184fe241c16da960c0b4de76816364b933344d0756 +vrfv2_proxy_admin: ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.bin 402b1103087ffe1aa598854a8f8b38f8cd3de2e3aaa86369e28017a9157f4980 vrfv2_reverting_example: ../../contracts/solc/v0.8.6/VRFV2RevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2RevertingExample.bin 1ae46f80351d428bd85ba58b9041b2a608a1845300d79a8fed83edf96606de87 -vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.bin 84be44ffac513ef5b009d53846b76d3247ceb9fa0545dec2a0dd11606a915850 -vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper.bin ccbacaaf7fa058ced4998a3811ad6af15f1be07db20548b945f7569b99d85cbc +vrfv2_transparent_upgradeable_proxy: ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.bin fe1a8e6852fbd06d91f64315c5cede86d340891f5b5cc981fb5b86563f7eac3f +vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper.bin d5e9a982325d2d4f517c4f2bc818795f61555408ef4b38fb59b923d144970e38 vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 -vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient.bin bec10896851c433bb5997c96d96d9871b335924a59a8ab07d7062fcbc3992c6e +vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample.bin 2c480a6d7955d33a00690fdd943486d95802e48a03f3cc243df314448e4ddb2c -vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.bin e5ae923d5fdfa916303cd7150b8474ccd912e14bafe950c6431f6ec94821f642 -vrfv2plus_reverting_example: ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.bin 34743ac1dd5e2c9d210b2bd721ebd4dff3c29c548f05582538690dde07773589 -vrfv2plus_wrapper: ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.bin 9099bc6d78c20ba502e2265d88825225649fa8a3402cb238f24f344ff239231a -vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.bin d4ddf86da21b87c013f551b2563ab68712ea9d4724894664d5778f6b124f4e78 -vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.bin 8212afe0f981cd0820f46f1e2e98219ce5d1b1eeae502730dbb52b8638f9ad44 +vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator.bin 80dbc98be5e42246960c889d29488f978d3db0127e95e9b295352c481d8c9b07 +vrfv2plus_reverting_example: ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusRevertingExample.bin 6c9053a94f90b8151964d3311310478b57744fbbd153e8ee742ed570e1e49798 +vrfv2plus_wrapper: ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapper.bin 934bafba386b934f491827e535306726069f4cafef9125079ea88abf0d808877 +vrfv2plus_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperConsumerExample.bin a14c4c6e2299cd963a8f0ed069e61dd135af5aad4c13a94f6ea7e086eced7191 +vrfv2plus_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2PlusWrapperLoadTestConsumer.bin 55e3bd534045125fb6579a201ab766185e9b0fac5737b4f37897bb69c9f599fa diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 6b1f952961a..ce553dc8186 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -13,19 +13,16 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.6/VRFRequestIDBaseTestHelper.bin VRFRequestIDBaseTestHelper solidity_vrf_request_id //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Flags.abi ../../contracts/solc/v0.6/Flags.bin Flags flags_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/Oracle.abi ../../contracts/solc/v0.6/Oracle.bin Oracle oracle_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/BlockhashStore.abi ../../contracts/solc/v0.6/BlockhashStore.bin BlockhashStore blockhash_store //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/TestAPIConsumer.abi ../../contracts/solc/v0.6/TestAPIConsumer.bin TestAPIConsumer test_api_consumer_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockETHLINKAggregator.abi ../../contracts/solc/v0.6/MockETHLINKAggregator.bin MockETHLINKAggregator mock_ethlink_aggregator_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.6/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator.bin MockGASAggregator mock_gas_aggregator_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/Consumer.abi ../../contracts/solc/v0.7/Consumer.bin Consumer consumer_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer.bin MultiWordConsumer multiwordconsumer_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/Operator.abi ../../contracts/solc/v0.7/Operator.bin Operator operator_wrapper -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/OperatorFactory.abi ../../contracts/solc/v0.7/OperatorFactory.bin OperatorFactory operator_factory -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/AuthorizedForwarder.abi ../../contracts/solc/v0.7/AuthorizedForwarder.bin AuthorizedForwarder authorized_forwarder -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.7/AuthorizedReceiver.abi ../../contracts/solc/v0.7/AuthorizedReceiver.bin AuthorizedReceiver authorized_receiver -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin BatchVRFCoordinatorV2 batch_vrf_coordinator_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/Operator.abi ../../contracts/solc/v0.8.19/Operator.bin Operator operator_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory.bin OperatorFactory operator_factory +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder.bin AuthorizedForwarder authorized_forwarder +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver.bin AuthorizedReceiver authorized_receiver //go:generate go run ./generation/generate/wrap.go OffchainAggregator/OffchainAggregator.abi - OffchainAggregator offchain_aggregator_wrapper // Automation @@ -65,6 +62,12 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup.bin LogTriggeredStreamsLookup log_triggered_streams_lookup_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/DummyProtocol.abi ../../contracts/solc/v0.8.16/DummyProtocol.bin DummyProtocol dummy_protocol_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer.bin KeeperConsumer keeper_consumer_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance.bin KeeperConsumerPerformance keeper_consumer_performance_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker.bin PerformDataChecker perform_data_checker_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepCounter.abi ../../contracts/solc/v0.8.16/UpkeepCounter.bin UpkeepCounter upkeep_counter_wrapper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.abi ../../contracts/solc/v0.8.16/UpkeepPerformCounterRestrictive.bin UpkeepPerformCounterRestrictive upkeep_perform_counter_restrictive_wrapper + // v0.8.6 VRFConsumer //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock.bin VRFCoordinatorMock vrf_coordinator_mock //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer.bin VRFConsumer solidity_vrf_consumer_interface_v08 @@ -74,10 +77,14 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner.bin VRFLoadTestExternalSubOwner vrf_load_test_external_sub_owner //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics.bin VRFV2LoadTestWithMetrics vrf_load_test_with_metrics //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer.bin VRFV2OwnerTestConsumer vrf_owner_test_consumer +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer.bin VRFv2Consumer vrf_v2_consumer_wrapper //go:generate go run ./generation/generate_link/wrap_link.go // VRF V2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore.bin BlockhashStore blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore.bin BatchBlockhashStore batch_blockhash_store +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2.bin BatchVRFCoordinatorV2 batch_vrf_coordinator_v2 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner.bin VRFOwner vrf_owner //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2.bin VRFCoordinatorV2 vrf_coordinator_v2 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFConsumerV2.abi ../../contracts/solc/v0.8.6/VRFConsumerV2.bin VRFConsumerV2 vrf_consumer_v2 @@ -94,8 +101,7 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy.bin VRFV2TransparentUpgradeableProxy vrfv2_transparent_upgradeable_proxy //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin.bin VRFV2ProxyAdmin vrfv2_proxy_admin - -// VRF V2 Plus +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper.bin ChainSpecificUtilHelper chain_specific_util_helper // VRF V2 Wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper @@ -128,7 +134,6 @@ package gethwrappers // Aggregators //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface.bin AggregatorV2V3Interface aggregator_v2v3_interface //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV3Interface.bin AggregatorV3Interface aggregator_v3_interface -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/DerivedPriceFeed.abi ../../contracts/solc/v0.8.6/DerivedPriceFeed.bin DerivedPriceFeed derived_price_feed_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy.bin MockAggregatorProxy mock_aggregator_proxy // Log tester @@ -150,11 +155,7 @@ package gethwrappers // 2. Generate events mock .sol files based on ABI of compiled contracts. // 3. Compile events mock contracts. ./generation/compile_event_mock_contract.sh calls contracts/scripts/native_solc_compile_all_events_mock to compile events mock contracts. // 4. Generate wrappers for events mock contracts. -//go:generate go run ./generation/generate_events_mock/create_events_mock_contract.go ../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracle.abi ../../contracts/src/v0.8/mocks/FunctionsOracleEventsMock.sol FunctionsOracleEventsMock -//go:generate go run ./generation/generate_events_mock/create_events_mock_contract.go ../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistry.abi ../../contracts/src/v0.8/mocks/FunctionsBillingRegistryEventsMock.sol FunctionsBillingRegistryEventsMock //go:generate ./generation/compile_event_mock_contract.sh -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsOracleEventsMock.bin FunctionsOracleEventsMock functions_oracle_events_mock -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock.abi ../../contracts/solc/v0.8.6/FunctionsBillingRegistryEventsMock.bin FunctionsBillingRegistryEventsMock functions_billing_registry_events_mock // Transmission //go:generate go generate ./transmission diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 4bb84a770a1..abc3b47db2c 100644 --- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -7,3 +7,4 @@ llo_feeds_test: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../con reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin db73e9062b17a1d5aa14c06881fe2be49bd95b00b7f1a8943910c5e4ded5b221 verifier: ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin df12786bbeccf3a8f3389479cf93c055b4efd5904b9f99a4835f81af43fe62bf verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin 6393443d0a323f2dbe9687dc30fd77f8dfa918944b61c651759746ff2d76e4e5 +werc20_mock: ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin ff2ca3928b2aa9c412c892cb8226c4d754c73eeb291bb7481c32c48791b2aa94 diff --git a/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go b/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go new file mode 100644 index 00000000000..3d8660c701d --- /dev/null +++ b/core/gethwrappers/shared/generated/werc20_mock/werc20_mock.go @@ -0,0 +1,1052 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package werc20_mock + +import ( + "errors" + "fmt" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var WERC20MockMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60806040523480156200001157600080fd5b506040518060400160405280600a8152602001695745524332304d6f636b60b01b815250604051806040016040528060048152602001635745524360e01b815250816003908162000063919062000120565b50600462000072828262000120565b505050620001ec565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620000a657607f821691505b602082108103620000c757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200011b57600081815260208120601f850160051c81016020861015620000f65750805b601f850160051c820191505b81811015620001175782815560010162000102565b5050505b505050565b81516001600160401b038111156200013c576200013c6200007b565b62000154816200014d845462000091565b84620000cd565b602080601f8311600181146200018c5760008415620001735750858301515b600019600386901b1c1916600185901b17855562000117565b600085815260208120601f198616915b82811015620001bd578886015182559484019460019091019084016200019c565b5085821015620001dc5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610fc980620001fc6000396000f3fe6080604052600436106100ec5760003560e01c806340c10f191161008a578063a457c2d711610059578063a457c2d71461028e578063a9059cbb146102ae578063d0e30db0146102ce578063dd62ed3e146102d657600080fd5b806340c10f19146101f657806370a082311461021657806395d89b41146102595780639dc29fac1461026e57600080fd5b806323b872dd116100c657806323b872dd1461017a5780632e1a7d4d1461019a578063313ce567146101ba57806339509351146101d657600080fd5b806306fdde0314610100578063095ea7b31461012b57806318160ddd1461015b57600080fd5b366100fb576100f9610329565b005b600080fd5b34801561010c57600080fd5b5061011561036a565b6040516101229190610dc6565b60405180910390f35b34801561013757600080fd5b5061014b610146366004610e5b565b6103fc565b6040519015158152602001610122565b34801561016757600080fd5b506002545b604051908152602001610122565b34801561018657600080fd5b5061014b610195366004610e85565b610416565b3480156101a657600080fd5b506100f96101b5366004610ec1565b61043a565b3480156101c657600080fd5b5060405160128152602001610122565b3480156101e257600080fd5b5061014b6101f1366004610e5b565b6104c6565b34801561020257600080fd5b506100f9610211366004610e5b565b610512565b34801561022257600080fd5b5061016c610231366004610eda565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b34801561026557600080fd5b50610115610520565b34801561027a57600080fd5b506100f9610289366004610e5b565b61052f565b34801561029a57600080fd5b5061014b6102a9366004610e5b565b610539565b3480156102ba57600080fd5b5061014b6102c9366004610e5b565b61060f565b6100f9610329565b3480156102e257600080fd5b5061016c6102f1366004610efc565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b610333333461061d565b60405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2565b60606003805461037990610f2f565b80601f01602080910402602001604051908101604052809291908181526020018280546103a590610f2f565b80156103f25780601f106103c7576101008083540402835291602001916103f2565b820191906000526020600020905b8154815290600101906020018083116103d557829003601f168201915b5050505050905090565b60003361040a818585610710565b60019150505b92915050565b6000336104248582856108c4565b61042f85858561099b565b506001949350505050565b3360009081526020819052604090205481111561045657600080fd5b6104603382610c0a565b604051339082156108fc029083906000818181858888f1935050505015801561048d573d6000803e3d6000fd5b5060405181815233907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a250565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919061040a908290869061050d908790610f82565b610710565b61051c828261061d565b5050565b60606004805461037990610f2f565b61051c8282610c0a565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610602576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61042f8286868403610710565b60003361040a81858561099b565b73ffffffffffffffffffffffffffffffffffffffff821661069a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016105f9565b80600260008282546106ac9190610f82565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff83166107b2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff8216610855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146109955781811015610988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016105f9565b6109958484848403610710565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610a3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff8216610ae1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610b97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610995565b73ffffffffffffffffffffffffffffffffffffffff8216610cad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015610d63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b73ffffffffffffffffffffffffffffffffffffffff83166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016108b7565b600060208083528351808285015260005b81811015610df357858101830151858201604001528201610dd7565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e5657600080fd5b919050565b60008060408385031215610e6e57600080fd5b610e7783610e32565b946020939093013593505050565b600080600060608486031215610e9a57600080fd5b610ea384610e32565b9250610eb160208501610e32565b9150604084013590509250925092565b600060208284031215610ed357600080fd5b5035919050565b600060208284031215610eec57600080fd5b610ef582610e32565b9392505050565b60008060408385031215610f0f57600080fd5b610f1883610e32565b9150610f2660208401610e32565b90509250929050565b600181811c90821680610f4357607f821691505b602082108103610f7c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b80820180821115610410577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea164736f6c6343000813000a", +} + +var WERC20MockABI = WERC20MockMetaData.ABI + +var WERC20MockBin = WERC20MockMetaData.Bin + +func DeployWERC20Mock(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *WERC20Mock, error) { + parsed, err := WERC20MockMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(WERC20MockBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &WERC20Mock{WERC20MockCaller: WERC20MockCaller{contract: contract}, WERC20MockTransactor: WERC20MockTransactor{contract: contract}, WERC20MockFilterer: WERC20MockFilterer{contract: contract}}, nil +} + +type WERC20Mock struct { + address common.Address + abi abi.ABI + WERC20MockCaller + WERC20MockTransactor + WERC20MockFilterer +} + +type WERC20MockCaller struct { + contract *bind.BoundContract +} + +type WERC20MockTransactor struct { + contract *bind.BoundContract +} + +type WERC20MockFilterer struct { + contract *bind.BoundContract +} + +type WERC20MockSession struct { + Contract *WERC20Mock + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type WERC20MockCallerSession struct { + Contract *WERC20MockCaller + CallOpts bind.CallOpts +} + +type WERC20MockTransactorSession struct { + Contract *WERC20MockTransactor + TransactOpts bind.TransactOpts +} + +type WERC20MockRaw struct { + Contract *WERC20Mock +} + +type WERC20MockCallerRaw struct { + Contract *WERC20MockCaller +} + +type WERC20MockTransactorRaw struct { + Contract *WERC20MockTransactor +} + +func NewWERC20Mock(address common.Address, backend bind.ContractBackend) (*WERC20Mock, error) { + abi, err := abi.JSON(strings.NewReader(WERC20MockABI)) + if err != nil { + return nil, err + } + contract, err := bindWERC20Mock(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &WERC20Mock{address: address, abi: abi, WERC20MockCaller: WERC20MockCaller{contract: contract}, WERC20MockTransactor: WERC20MockTransactor{contract: contract}, WERC20MockFilterer: WERC20MockFilterer{contract: contract}}, nil +} + +func NewWERC20MockCaller(address common.Address, caller bind.ContractCaller) (*WERC20MockCaller, error) { + contract, err := bindWERC20Mock(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &WERC20MockCaller{contract: contract}, nil +} + +func NewWERC20MockTransactor(address common.Address, transactor bind.ContractTransactor) (*WERC20MockTransactor, error) { + contract, err := bindWERC20Mock(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &WERC20MockTransactor{contract: contract}, nil +} + +func NewWERC20MockFilterer(address common.Address, filterer bind.ContractFilterer) (*WERC20MockFilterer, error) { + contract, err := bindWERC20Mock(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &WERC20MockFilterer{contract: contract}, nil +} + +func bindWERC20Mock(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := WERC20MockMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_WERC20Mock *WERC20MockRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _WERC20Mock.Contract.WERC20MockCaller.contract.Call(opts, result, method, params...) +} + +func (_WERC20Mock *WERC20MockRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WERC20Mock.Contract.WERC20MockTransactor.contract.Transfer(opts) +} + +func (_WERC20Mock *WERC20MockRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _WERC20Mock.Contract.WERC20MockTransactor.contract.Transact(opts, method, params...) +} + +func (_WERC20Mock *WERC20MockCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _WERC20Mock.Contract.contract.Call(opts, result, method, params...) +} + +func (_WERC20Mock *WERC20MockTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WERC20Mock.Contract.contract.Transfer(opts) +} + +func (_WERC20Mock *WERC20MockTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _WERC20Mock.Contract.contract.Transact(opts, method, params...) +} + +func (_WERC20Mock *WERC20MockCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _WERC20Mock.Contract.Allowance(&_WERC20Mock.CallOpts, owner, spender) +} + +func (_WERC20Mock *WERC20MockCallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _WERC20Mock.Contract.Allowance(&_WERC20Mock.CallOpts, owner, spender) +} + +func (_WERC20Mock *WERC20MockCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) BalanceOf(account common.Address) (*big.Int, error) { + return _WERC20Mock.Contract.BalanceOf(&_WERC20Mock.CallOpts, account) +} + +func (_WERC20Mock *WERC20MockCallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _WERC20Mock.Contract.BalanceOf(&_WERC20Mock.CallOpts, account) +} + +func (_WERC20Mock *WERC20MockCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) Decimals() (uint8, error) { + return _WERC20Mock.Contract.Decimals(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCallerSession) Decimals() (uint8, error) { + return _WERC20Mock.Contract.Decimals(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) Name() (string, error) { + return _WERC20Mock.Contract.Name(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCallerSession) Name() (string, error) { + return _WERC20Mock.Contract.Name(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) Symbol() (string, error) { + return _WERC20Mock.Contract.Symbol(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCallerSession) Symbol() (string, error) { + return _WERC20Mock.Contract.Symbol(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _WERC20Mock.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_WERC20Mock *WERC20MockSession) TotalSupply() (*big.Int, error) { + return _WERC20Mock.Contract.TotalSupply(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockCallerSession) TotalSupply() (*big.Int, error) { + return _WERC20Mock.Contract.TotalSupply(&_WERC20Mock.CallOpts) +} + +func (_WERC20Mock *WERC20MockTransactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "approve", spender, amount) +} + +func (_WERC20Mock *WERC20MockSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Approve(&_WERC20Mock.TransactOpts, spender, amount) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Approve(&_WERC20Mock.TransactOpts, spender, amount) +} + +func (_WERC20Mock *WERC20MockTransactor) Burn(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "burn", account, amount) +} + +func (_WERC20Mock *WERC20MockSession) Burn(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Burn(&_WERC20Mock.TransactOpts, account, amount) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Burn(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Burn(&_WERC20Mock.TransactOpts, account, amount) +} + +func (_WERC20Mock *WERC20MockTransactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) +} + +func (_WERC20Mock *WERC20MockSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.DecreaseAllowance(&_WERC20Mock.TransactOpts, spender, subtractedValue) +} + +func (_WERC20Mock *WERC20MockTransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.DecreaseAllowance(&_WERC20Mock.TransactOpts, spender, subtractedValue) +} + +func (_WERC20Mock *WERC20MockTransactor) Deposit(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "deposit") +} + +func (_WERC20Mock *WERC20MockSession) Deposit() (*types.Transaction, error) { + return _WERC20Mock.Contract.Deposit(&_WERC20Mock.TransactOpts) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Deposit() (*types.Transaction, error) { + return _WERC20Mock.Contract.Deposit(&_WERC20Mock.TransactOpts) +} + +func (_WERC20Mock *WERC20MockTransactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "increaseAllowance", spender, addedValue) +} + +func (_WERC20Mock *WERC20MockSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.IncreaseAllowance(&_WERC20Mock.TransactOpts, spender, addedValue) +} + +func (_WERC20Mock *WERC20MockTransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.IncreaseAllowance(&_WERC20Mock.TransactOpts, spender, addedValue) +} + +func (_WERC20Mock *WERC20MockTransactor) Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "mint", account, amount) +} + +func (_WERC20Mock *WERC20MockSession) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Mint(&_WERC20Mock.TransactOpts, account, amount) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Mint(&_WERC20Mock.TransactOpts, account, amount) +} + +func (_WERC20Mock *WERC20MockTransactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "transfer", to, amount) +} + +func (_WERC20Mock *WERC20MockSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Transfer(&_WERC20Mock.TransactOpts, to, amount) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Transfer(&_WERC20Mock.TransactOpts, to, amount) +} + +func (_WERC20Mock *WERC20MockTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "transferFrom", from, to, amount) +} + +func (_WERC20Mock *WERC20MockSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.TransferFrom(&_WERC20Mock.TransactOpts, from, to, amount) +} + +func (_WERC20Mock *WERC20MockTransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.TransferFrom(&_WERC20Mock.TransactOpts, from, to, amount) +} + +func (_WERC20Mock *WERC20MockTransactor) Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error) { + return _WERC20Mock.contract.Transact(opts, "withdraw", wad) +} + +func (_WERC20Mock *WERC20MockSession) Withdraw(wad *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Withdraw(&_WERC20Mock.TransactOpts, wad) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Withdraw(wad *big.Int) (*types.Transaction, error) { + return _WERC20Mock.Contract.Withdraw(&_WERC20Mock.TransactOpts, wad) +} + +func (_WERC20Mock *WERC20MockTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WERC20Mock.contract.RawTransact(opts, nil) +} + +func (_WERC20Mock *WERC20MockSession) Receive() (*types.Transaction, error) { + return _WERC20Mock.Contract.Receive(&_WERC20Mock.TransactOpts) +} + +func (_WERC20Mock *WERC20MockTransactorSession) Receive() (*types.Transaction, error) { + return _WERC20Mock.Contract.Receive(&_WERC20Mock.TransactOpts) +} + +type WERC20MockApprovalIterator struct { + Event *WERC20MockApproval + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *WERC20MockApprovalIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(WERC20MockApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(WERC20MockApproval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *WERC20MockApprovalIterator) Error() error { + return it.fail +} + +func (it *WERC20MockApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type WERC20MockApproval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log +} + +func (_WERC20Mock *WERC20MockFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*WERC20MockApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _WERC20Mock.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &WERC20MockApprovalIterator{contract: _WERC20Mock.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +func (_WERC20Mock *WERC20MockFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *WERC20MockApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _WERC20Mock.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(WERC20MockApproval) + if err := _WERC20Mock.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_WERC20Mock *WERC20MockFilterer) ParseApproval(log types.Log) (*WERC20MockApproval, error) { + event := new(WERC20MockApproval) + if err := _WERC20Mock.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type WERC20MockDepositIterator struct { + Event *WERC20MockDeposit + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *WERC20MockDepositIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(WERC20MockDeposit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(WERC20MockDeposit) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *WERC20MockDepositIterator) Error() error { + return it.fail +} + +func (it *WERC20MockDepositIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type WERC20MockDeposit struct { + Dst common.Address + Wad *big.Int + Raw types.Log +} + +func (_WERC20Mock *WERC20MockFilterer) FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WERC20MockDepositIterator, error) { + + var dstRule []interface{} + for _, dstItem := range dst { + dstRule = append(dstRule, dstItem) + } + + logs, sub, err := _WERC20Mock.contract.FilterLogs(opts, "Deposit", dstRule) + if err != nil { + return nil, err + } + return &WERC20MockDepositIterator{contract: _WERC20Mock.contract, event: "Deposit", logs: logs, sub: sub}, nil +} + +func (_WERC20Mock *WERC20MockFilterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *WERC20MockDeposit, dst []common.Address) (event.Subscription, error) { + + var dstRule []interface{} + for _, dstItem := range dst { + dstRule = append(dstRule, dstItem) + } + + logs, sub, err := _WERC20Mock.contract.WatchLogs(opts, "Deposit", dstRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(WERC20MockDeposit) + if err := _WERC20Mock.contract.UnpackLog(event, "Deposit", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_WERC20Mock *WERC20MockFilterer) ParseDeposit(log types.Log) (*WERC20MockDeposit, error) { + event := new(WERC20MockDeposit) + if err := _WERC20Mock.contract.UnpackLog(event, "Deposit", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type WERC20MockTransferIterator struct { + Event *WERC20MockTransfer + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *WERC20MockTransferIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(WERC20MockTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(WERC20MockTransfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *WERC20MockTransferIterator) Error() error { + return it.fail +} + +func (it *WERC20MockTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type WERC20MockTransfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log +} + +func (_WERC20Mock *WERC20MockFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*WERC20MockTransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _WERC20Mock.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &WERC20MockTransferIterator{contract: _WERC20Mock.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +func (_WERC20Mock *WERC20MockFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *WERC20MockTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _WERC20Mock.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(WERC20MockTransfer) + if err := _WERC20Mock.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_WERC20Mock *WERC20MockFilterer) ParseTransfer(log types.Log) (*WERC20MockTransfer, error) { + event := new(WERC20MockTransfer) + if err := _WERC20Mock.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type WERC20MockWithdrawalIterator struct { + Event *WERC20MockWithdrawal + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *WERC20MockWithdrawalIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(WERC20MockWithdrawal) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(WERC20MockWithdrawal) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *WERC20MockWithdrawalIterator) Error() error { + return it.fail +} + +func (it *WERC20MockWithdrawalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type WERC20MockWithdrawal struct { + Src common.Address + Wad *big.Int + Raw types.Log +} + +func (_WERC20Mock *WERC20MockFilterer) FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WERC20MockWithdrawalIterator, error) { + + var srcRule []interface{} + for _, srcItem := range src { + srcRule = append(srcRule, srcItem) + } + + logs, sub, err := _WERC20Mock.contract.FilterLogs(opts, "Withdrawal", srcRule) + if err != nil { + return nil, err + } + return &WERC20MockWithdrawalIterator{contract: _WERC20Mock.contract, event: "Withdrawal", logs: logs, sub: sub}, nil +} + +func (_WERC20Mock *WERC20MockFilterer) WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WERC20MockWithdrawal, src []common.Address) (event.Subscription, error) { + + var srcRule []interface{} + for _, srcItem := range src { + srcRule = append(srcRule, srcItem) + } + + logs, sub, err := _WERC20Mock.contract.WatchLogs(opts, "Withdrawal", srcRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(WERC20MockWithdrawal) + if err := _WERC20Mock.contract.UnpackLog(event, "Withdrawal", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_WERC20Mock *WERC20MockFilterer) ParseWithdrawal(log types.Log) (*WERC20MockWithdrawal, error) { + event := new(WERC20MockWithdrawal) + if err := _WERC20Mock.contract.UnpackLog(event, "Withdrawal", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_WERC20Mock *WERC20Mock) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _WERC20Mock.abi.Events["Approval"].ID: + return _WERC20Mock.ParseApproval(log) + case _WERC20Mock.abi.Events["Deposit"].ID: + return _WERC20Mock.ParseDeposit(log) + case _WERC20Mock.abi.Events["Transfer"].ID: + return _WERC20Mock.ParseTransfer(log) + case _WERC20Mock.abi.Events["Withdrawal"].ID: + return _WERC20Mock.ParseWithdrawal(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (WERC20MockApproval) Topic() common.Hash { + return common.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925") +} + +func (WERC20MockDeposit) Topic() common.Hash { + return common.HexToHash("0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c") +} + +func (WERC20MockTransfer) Topic() common.Hash { + return common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") +} + +func (WERC20MockWithdrawal) Topic() common.Hash { + return common.HexToHash("0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65") +} + +func (_WERC20Mock *WERC20Mock) Address() common.Address { + return _WERC20Mock.address +} + +type WERC20MockInterface interface { + Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) + + BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) + + Decimals(opts *bind.CallOpts) (uint8, error) + + Name(opts *bind.CallOpts) (string, error) + + Symbol(opts *bind.CallOpts) (string, error) + + TotalSupply(opts *bind.CallOpts) (*big.Int, error) + + Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) + + Burn(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) + + DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) + + Deposit(opts *bind.TransactOpts) (*types.Transaction, error) + + IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) + + Mint(opts *bind.TransactOpts, account common.Address, amount *big.Int) (*types.Transaction, error) + + Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) + + TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) + + Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error) + + Receive(opts *bind.TransactOpts) (*types.Transaction, error) + + FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*WERC20MockApprovalIterator, error) + + WatchApproval(opts *bind.WatchOpts, sink chan<- *WERC20MockApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) + + ParseApproval(log types.Log) (*WERC20MockApproval, error) + + FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WERC20MockDepositIterator, error) + + WatchDeposit(opts *bind.WatchOpts, sink chan<- *WERC20MockDeposit, dst []common.Address) (event.Subscription, error) + + ParseDeposit(log types.Log) (*WERC20MockDeposit, error) + + FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*WERC20MockTransferIterator, error) + + WatchTransfer(opts *bind.WatchOpts, sink chan<- *WERC20MockTransfer, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseTransfer(log types.Log) (*WERC20MockTransfer, error) + + FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WERC20MockWithdrawalIterator, error) + + WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WERC20MockWithdrawal, src []common.Address) (event.Subscription, error) + + ParseWithdrawal(log types.Log) (*WERC20MockWithdrawal, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 3094b1a94f0..7ac7e77a4b8 100644 --- a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -2,3 +2,4 @@ GETH_VERSION: 1.12.0 burn_mint_erc677: ../../../contracts/solc/v0.8.19/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677.bin 405c9016171e614b17e10588653ef8d33dcea21dd569c3fddc596a46fcff68a3 erc20: ../../../contracts/solc/v0.8.19/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20.bin 5b1a93d9b24f250e49a730c96335a8113c3f7010365cba578f313b483001d4fc link_token: ../../../contracts/solc/v0.8.19/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken.bin c0ef9b507103aae541ebc31d87d051c2764ba9d843076b30ec505d37cdfffaba +werc20_mock: ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin ff2ca3928b2aa9c412c892cb8226c4d754c73eeb291bb7481c32c48791b2aa94 diff --git a/core/gethwrappers/shared/go_generate.go b/core/gethwrappers/shared/go_generate.go index 169a87b9b2d..85a01670c9a 100644 --- a/core/gethwrappers/shared/go_generate.go +++ b/core/gethwrappers/shared/go_generate.go @@ -5,3 +5,4 @@ package gethwrappers //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677.bin BurnMintERC677 burn_mint_erc677 //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken.bin LinkToken link_token //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20.bin ERC20 erc20 +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/WERC20Mock.abi ../../../contracts/solc/v0.8.19/WERC20Mock.bin WERC20Mock werc20_mock diff --git a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go index 4bf2e75b97f..add1d2ce51b 100644 --- a/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go +++ b/core/gethwrappers/transmission/generated/smart_contract_account_helper/smart_contract_account_helper.go @@ -29,7 +29,7 @@ var ( ) var SmartContractAccountHelperMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"}],\"name\":\"calculateSmartContractAccountAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"topupThreshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"topupAmount\",\"type\":\"uint256\"}],\"name\":\"getAbiEncodedDirectRequestData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"endContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getFullEndTxEncoding\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"encoding\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"scaAddress\",\"type\":\"address\"}],\"name\":\"getFullHashForSigning\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getInitCode\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getSCAInitCodeWithConstructor\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"}],\"name\":\"calculateSmartContractAccountAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"topupThreshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"topupAmount\",\"type\":\"uint256\"}],\"name\":\"getAbiEncodedDirectRequestData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"endContract\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getFullEndTxEncoding\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"encoding\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"userOpHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"scaAddress\",\"type\":\"address\"}],\"name\":\"getFullHashForSigning\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getInitCode\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"entryPoint\",\"type\":\"address\"}],\"name\":\"getSCAInitCodeWithConstructor\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"initCode\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", Bin: "0x61162261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061007c5760003560e01c8063e0237bef1161005a578063e0237bef14610134578063e464b3631461016c578063fc59bac31461017f57600080fd5b80632c86cb35146100815780634b770f561461010057806382311e3314610113575b600080fd5b6100ea61008f36600461076b565b604080516060808201835273ffffffffffffffffffffffffffffffffffffffff959095168082526020808301958652918301938452825191820152925183820152905182840152805180830390930183526080909101905290565b6040516100f79190610818565b60405180910390f35b6100ea61010e36600461082b565b610192565b61012661012136600461086e565b610336565b6040519081526020016100f7565b61014761014236600461082b565b610454565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f7565b6100ea61017a36600461089a565b6105df565b6100ea61018d3660046108f3565b61069d565b6040516060907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000084831b16906000906101cd60208201610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8881166020840152871690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261026292916020016109e6565b60405160208183030381529060405290508560601b630af4926f60e01b8383604051602401610292929190610a15565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909516949094179093525161031c939201610a36565b604051602081830303815290604052925050509392505050565b600061044d8383604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b9392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1690829061049060208201610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8981166020840152881690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261052592916020016109e6565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201207fff000000000000000000000000000000000000000000000000000000000000008285015260609790971b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166021840152603583019490945260558083019690965280518083039096018652607590910190525082519201919091209392505050565b6060604051806020016105f190610735565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604081815273ffffffffffffffffffffffffffffffffffffffff8681166020840152851690820152606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261068692916020016109e6565b604051602081830303815290604052905092915050565b60607f89553be40000000000000000000000000000000000000000000000000000000085856106cc8642610a7e565b856040516020016106e09493929190610abd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261071c9291602001610b02565b6040516020818303038152906040529050949350505050565b610acb80610b4b83390190565b803573ffffffffffffffffffffffffffffffffffffffff8116811461076657600080fd5b919050565b60008060006060848603121561078057600080fd5b61078984610742565b95602085013595506040909401359392505050565b60005b838110156107b95781810151838201526020016107a1565b838111156107c8576000848401525b50505050565b600081518084526107e681602086016020860161079e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061044d60208301846107ce565b60008060006060848603121561084057600080fd5b61084984610742565b925061085760208501610742565b915061086560408501610742565b90509250925092565b6000806040838503121561088157600080fd5b8235915061089160208401610742565b90509250929050565b600080604083850312156108ad57600080fd5b6108b683610742565b915061089160208401610742565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561090957600080fd5b61091285610742565b93506020850135925060408501359150606085013567ffffffffffffffff8082111561093d57600080fd5b818701915087601f83011261095157600080fd5b813581811115610963576109636108c4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109a9576109a96108c4565b816040528281528a60208487010111156109c257600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600083516109f881846020880161079e565b835190830190610a0c81836020880161079e565b01949350505050565b828152604060208201526000610a2e60408301846107ce565b949350505050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008316815260008251610a7081601485016020870161079e565b919091016014019392505050565b60008219821115610ab8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000610af860808301846107ce565b9695505050505050565b7fffffffff000000000000000000000000000000000000000000000000000000008316815260008251610b3c81600485016020870161079e565b91909101600401939250505056fe60c060405234801561001057600080fd5b50604051610acb380380610acb83398101604081905261002f91610062565b6001600160a01b039182166080521660a052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a051610a046100c760003960008181607101526103c301526000818161010101526102ee0152610a046000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637eccf63e116100505780637eccf63e146100de57806389553be4146100e7578063dba6335f146100fc57600080fd5b8063140fcfb11461006c5780633a871cdd146100bd575b600080fd5b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d06100cb36600461063a565b610123565b6040519081526020016100b4565b6100d060005481565b6100fa6100f53660046106ce565b6103ab565b005b6100937f000000000000000000000000000000000000000000000000000000000000000081565b60008054846020013514610179576000546040517f7ba633940000000000000000000000000000000000000000000000000000000081526004810191909152602085013560248201526044015b60405180910390fd5b60006102908430604080517f4750045d47fce615521b32cee713ff8db50147e98aec5ca94926b52651ca3fa060208083019190915281830194909452815180820383018152606080830184528151918601919091207f190000000000000000000000000000000000000000000000000000000000000060808401527f010000000000000000000000000000000000000000000000000000000000000060818401527f1c7d3b72b37a35523e273aaadd7b4cd66f618bb81429ab053412d51f50ccea6160828401524660a284015293901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660c282015260d6808201939093528151808203909301835260f6019052805191012090565b905060006102a261014087018761076b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016915061031c90508284610544565b73ffffffffffffffffffffffffffffffffffffffff161461034d576103446001600080610602565b925050506103a4565b60008054908061035c83610806565b9091555060009050610371606088018861076b565b61037f91600490829061083e565b81019061038c9190610897565b509250505061039e6000826000610602565b93505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461041c576040517f4a0bfec1000000000000000000000000000000000000000000000000000000008152336004820152602401610170565b65ffffffffffff83161580159061043a57508265ffffffffffff1642115b15610481576040517f300249d700000000000000000000000000000000000000000000000000000000815265ffffffffffff84166004820152426024820152604401610170565b6000808673ffffffffffffffffffffffffffffffffffffffff168685856040516104ac929190610993565b60006040518083038185875af1925050503d80600081146104e9576040519150601f19603f3d011682016040523d82523d6000602084013e6104ee565b606091505b50915091508161053b578051600003610533576040517f20e9b5d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805181602001fd5b50505050505050565b602082015160408084015184516000939284918791908110610568576105686109a3565b016020015160f81c905060018561058083601b6109d2565b6040805160008152602081018083529390935260ff90911690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156105cf573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151979650505050505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b8561062a57600061062d565b60015b60ff161717949350505050565b60008060006060848603121561064f57600080fd5b833567ffffffffffffffff81111561066657600080fd5b8401610160818703121561067957600080fd5b95602085013595506040909401359392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146106b057600080fd5b50565b803565ffffffffffff811681146106c957600080fd5b919050565b6000806000806000608086880312156106e657600080fd5b85356106f18161068e565b945060208601359350610706604087016106b3565b9250606086013567ffffffffffffffff8082111561072357600080fd5b818801915088601f83011261073757600080fd5b81358181111561074657600080fd5b89602082850101111561075857600080fd5b9699959850939650602001949392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107a057600080fd5b83018035915067ffffffffffffffff8211156107bb57600080fd5b6020019150368190038213156107d057600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610837576108376107d7565b5060010190565b6000808585111561084e57600080fd5b8386111561085b57600080fd5b5050820193919092039150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080600080608085870312156108ad57600080fd5b84356108b88161068e565b9350602085013592506108cd604086016106b3565b9150606085013567ffffffffffffffff808211156108ea57600080fd5b818701915087601f8301126108fe57600080fd5b81358181111561091057610910610868565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561095657610956610868565b816040528281528a602084870101111561096f57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060ff821660ff84168060ff038211156109ef576109ef6107d7565b01939250505056fea164736f6c634300080f000aa164736f6c634300080f000a", } diff --git a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 3a0a324c80e..8ea0492fa40 100644 --- a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -6,4 +6,4 @@ paymaster_wrapper: ../../../contracts/solc/v0.8.15/Paymaster.abi ../../../contra sca: ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin ae0f860cdac87d4ac505edbd228bd3ea1108550453aba67aebcb61f09cf70d0b sca_wrapper: ../../../contracts/solc/v0.8.15/SCA.abi ../../../contracts/solc/v0.8.15/SCA.bin 2a8100fbdb41e6ce917ed333a624eaa4a8984b07e2d8d8ca6bba9bc9f74b05d7 smart_contract_account_factory: ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.abi ../../../contracts/solc/v0.8.15/SmartContractAccountFactory.bin a44d6fa2dbf9cb3441d6d637d89e1cd656f28b6bf4146f58d508067474bf845b -smart_contract_account_helper: ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.bin 0db06d3fdb558d152c13bed492301179ea0fcdc6f992990291f1ecabbf836bb9 +smart_contract_account_helper: ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.abi ../../../contracts/solc/v0.8.15/SmartContractAccountHelper.bin 22f960a74bd1581a12aa4f8f438a3f265f32f43682f5c1897ca50707b9982d56 diff --git a/core/gethwrappers/versions.go b/core/gethwrappers/versions.go index 5b65e2f411a..acdefd06a59 100644 --- a/core/gethwrappers/versions.go +++ b/core/gethwrappers/versions.go @@ -54,7 +54,7 @@ func versionsDBLineReader() (*bufio.Scanner, error) { } -// readVersionsDB populates an IntegratedVersion with all the info in the +// ReadVersionsDB populates an IntegratedVersion with all the info in the // versions DB func ReadVersionsDB() (*IntegratedVersion, error) { rv := IntegratedVersion{} @@ -87,7 +87,7 @@ func ReadVersionsDB() (*IntegratedVersion, error) { } _, alreadyExists := rv.ContractVersions[topic] if alreadyExists { - return nil, errors.Errorf(`topic "%s" already mentioned!`, topic) + return nil, errors.Errorf(`topic "%s" already mentioned`, topic) } rv.ContractVersions[topic] = ContractVersion{ AbiPath: line[1], BinaryPath: line[2], Hash: line[3], diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 671d4072816..a9ff8144b3c 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -33,14 +33,15 @@ import ( p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/manyminds/api2go/jsonapi" "github.com/onsi/gomega" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" "github.com/urfave/cli" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" clienttypes "github.com/smartcontractkit/chainlink/v2/common/chains/client" @@ -97,10 +98,6 @@ import ( ) const ( - // APIKey of the fixture API user - APIKey = "2d25e62eaf9143e993acaf48691564b2" - // APISecret of the fixture API user. - APISecret = "1eCP/w0llVkchejFaoBpfIGaLRxZK54lTXBCT22YLW+pdzE4Fafy/XO5LoJ2uwHi" // Collection of test fixture DB user emails per role APIEmailAdmin = "apiuser@chainlink.test" APIEmailEdit = "apiuser-edit@chainlink.test" @@ -209,8 +206,7 @@ func NewEventBroadcaster(t testing.TB, dbURL url.URL) pg.EventBroadcaster { return pg.NewEventBroadcaster(dbURL, 0, 0, lggr, uuid.New()) } -func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) (*txmgr.Confirmer, error) { - t.Helper() +func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) @@ -218,7 +214,7 @@ func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) require.NoError(t, ec.Start(testutils.Context(t))) - return ec, nil + return ec } // TestApplication holds the test application and test servers @@ -271,8 +267,6 @@ func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestAppli // NewApplicationWithConfigAndKey creates a new TestApplication with the given testorm // it will also provide an unlocked account on the keystore func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, flagsAndDeps ...interface{}) *TestApplication { - t.Helper() - app := NewApplicationWithConfig(t, c, flagsAndDeps...) chainID := *utils.NewBig(&FixtureChainID) @@ -284,12 +278,14 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla } if len(app.Keys) == 0 { - k, _ := MustInsertRandomKey(t, app.KeyStore.Eth(), 0, chainID) + k, _ := MustInsertRandomKey(t, app.KeyStore.Eth(), chainID) app.Keys = []ethkey.KeyV2{k} } else { id, ks := chainID.ToInt(), app.KeyStore.Eth() for _, k := range app.Keys { - MustAddKeyToKeystore(t, k, id, ks) + ks.XXXTestingOnlyAdd(k) + require.NoError(t, ks.Add(k.Address, id)) + require.NoError(t, ks.Enable(k.Address, id)) } } @@ -379,10 +375,10 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } } - keyStore := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) + keyStore := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) - loopRegistry := plugins.NewLoopRegistry(lggr) + loopRegistry := plugins.NewLoopRegistry(lggr, nil) relayerFactory := chainlink.RelayerFactory{ Logger: lggr, @@ -429,15 +425,15 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } if cfg.SolanaEnabled() { solanaCfg := chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - SolanaConfigs: cfg.SolanaConfigs(), + Keystore: keyStore.Solana(), + TOMLConfigs: cfg.SolanaConfigs(), } initOps = append(initOps, chainlink.InitSolana(testCtx, relayerFactory, solanaCfg)) } if cfg.StarkNetEnabled() { starkCfg := chainlink.StarkNetFactoryConfig{ - Keystore: keyStore.StarkNet(), - StarknetConfigs: cfg.StarknetConfigs(), + Keystore: keyStore.StarkNet(), + TOMLConfigs: cfg.StarknetConfigs(), } initOps = append(initOps, chainlink.InitStarknet(testCtx, relayerFactory, starkCfg)) @@ -461,7 +457,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn RestrictedHTTPClient: c, UnrestrictedHTTPClient: c, SecretGenerator: MockSecretGenerator{}, - LoopRegistry: plugins.NewLoopRegistry(lggr), + LoopRegistry: plugins.NewLoopRegistry(lggr, nil), }) require.NoError(t, err) app := appInstance.(*chainlink.ChainlinkApplication) @@ -619,6 +615,10 @@ type User struct { func (ta *TestApplication) NewHTTPClient(user *User) HTTPClientCleaner { ta.t.Helper() + if user == nil { + user = &User{} + } + if user.Email == "" { user.Email = fmt.Sprintf("%s@chainlink.test", uuid.New()) } @@ -647,7 +647,7 @@ func (ta *TestApplication) NewClientOpts() cmd.ClientOpts { // NewShellAndRenderer creates a new cmd.Shell for the test application func (ta *TestApplication) NewShellAndRenderer() (*cmd.Shell, *RendererMock) { - hc := ta.NewHTTPClient(&User{}) + hc := ta.NewHTTPClient(nil) r := &RendererMock{} lggr := logger.TestLogger(ta.t) client := &cmd.Shell{ @@ -687,7 +687,7 @@ func (ta *TestApplication) NewAuthenticatingShell(prompter cmd.Prompter) *cmd.Sh // NewKeyStore returns a new, unlocked keystore func NewKeyStore(t testing.TB, db *sqlx.DB, cfg pg.QConfig) keystore.Master { - keystore := keystore.New(db, utils.FastScryptParams, logger.TestLogger(t), cfg) + keystore := keystore.NewInMemory(db, utils.FastScryptParams, logger.TestLogger(t), cfg) require.NoError(t, keystore.Unlock(Password)) return keystore } @@ -809,7 +809,7 @@ func ParseJSONAPIResponseMetaCount(input []byte) (int, error) { func CreateJobViaWeb(t testing.TB, app *TestApplication, request []byte) job.Job { t.Helper() - client := app.NewHTTPClient(&User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/jobs", bytes.NewBuffer(request)) defer cleanup() AssertServerResponse(t, resp, http.StatusOK) @@ -823,7 +823,7 @@ func CreateJobViaWeb(t testing.TB, app *TestApplication, request []byte) job.Job func CreateJobViaWeb2(t testing.TB, app *TestApplication, spec string) webpresenters.JobResource { t.Helper() - client := app.NewHTTPClient(&User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/jobs", bytes.NewBufferString(spec)) defer cleanup() AssertServerResponse(t, resp, http.StatusOK) @@ -837,7 +837,7 @@ func CreateJobViaWeb2(t testing.TB, app *TestApplication, spec string) webpresen func DeleteJobViaWeb(t testing.TB, app *TestApplication, jobID int32) { t.Helper() - client := app.NewHTTPClient(&User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Delete(fmt.Sprintf("/v2/jobs/%v", jobID)) defer cleanup() AssertServerResponse(t, resp, http.StatusNoContent) @@ -886,7 +886,7 @@ func CreateJobRunViaUser( t.Helper() bodyBuf := bytes.NewBufferString(body) - client := app.NewHTTPClient(&User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/jobs/"+jobID.String()+"/runs", bodyBuf) defer cleanup() AssertServerResponse(t, resp, 200) @@ -905,7 +905,7 @@ func CreateExternalInitiatorViaWeb( ) *webpresenters.ExternalInitiatorAuthentication { t.Helper() - client := app.NewHTTPClient(&User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post( "/v2/external_initiators", bytes.NewBufferString(payload), @@ -1331,51 +1331,24 @@ func BatchElemMustMatchParams(t *testing.T, req rpc.BatchElem, hash common.Hash, } } -type SimulateIncomingHeadsArgs struct { - StartBlock, EndBlock int64 - HeadTrackables []httypes.HeadTrackable - Blocks *Blocks -} - // SimulateIncomingHeads spawns a goroutine which sends a stream of heads and closes the returned channel when finished. -func SimulateIncomingHeads(t *testing.T, args SimulateIncomingHeadsArgs) (done chan struct{}) { - t.Helper() - lggr := logger.TestLogger(t).Named("SimulateIncomingHeads") - lggr.Infof("Simulating incoming heads from %v to %v...", args.StartBlock, args.EndBlock) - - if args.EndBlock > args.StartBlock { - if l := 1 + args.EndBlock - args.StartBlock; l > int64(len(args.Blocks.Heads)) { - t.Fatalf("invalid configuration: too few blocks %d for range length %d", len(args.Blocks.Heads), l) - } - } - +func SimulateIncomingHeads(t *testing.T, heads []*evmtypes.Head, headTrackables ...httypes.HeadTrackable) (done chan struct{}) { // Build the full chain of heads - heads := args.Blocks.Heads - ctx, cancel := context.WithTimeout(context.Background(), testutils.WaitTimeout(t)) - t.Cleanup(cancel) + ctx := testutils.Context(t) done = make(chan struct{}) go func(t *testing.T) { defer close(done) ticker := time.NewTicker(250 * time.Millisecond) defer ticker.Stop() - for current := args.StartBlock; ; current++ { + for _, h := range heads { select { case <-ctx.Done(): return case <-ticker.C: - _, exists := heads[current] - if !exists { - lggr.Infof("Out of heads: %d does not exist", current) - return - } - - lggr.Infof("Sending head: %d", current) - for _, ht := range args.HeadTrackables { - ht.OnNewLongestChain(ctx, heads[current]) - } - if args.EndBlock >= 0 && current == args.EndBlock { - return + t.Logf("Sending head: %d", h.Number) + for _, ht := range headTrackables { + ht.OnNewLongestChain(ctx, h) } } } @@ -1452,6 +1425,33 @@ func (b *Blocks) NewHead(number uint64) *evmtypes.Head { return head } +// Slice returns a slice of heads from number i to j. Set j < 0 for all remaining. +func (b *Blocks) Slice(i, j int) []*evmtypes.Head { + b.t.Logf("Slicing heads from %v to %v...", i, j) + + if j > 0 && j-i > len(b.Heads) { + b.t.Fatalf("invalid configuration: too few blocks %d for range length %d", len(b.Heads), j-i) + } + return b.slice(i, j) +} + +func (b *Blocks) slice(i, j int) (heads []*evmtypes.Head) { + if j > 0 { + heads = make([]*evmtypes.Head, 0, j-i) + } + for n := i; j < 0 || n < j; n++ { + h, ok := b.Heads[int64(n)] + if !ok { + if j < 0 { + break // done + } + b.t.Fatalf("invalid configuration: block %d not found", n) + } + heads = append(heads, h) + } + return +} + func NewBlocks(t *testing.T, numHashes int) *Blocks { hashes := make([]common.Hash, 0) heads := make(map[int64]*evmtypes.Head) diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index cb0b51743e4..a1a5d9db6be 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -368,7 +368,7 @@ func MustCreateUnstartedTx(t testing.TB, txStore txmgr.EvmTxStore, fromAddress c } func MustCreateUnstartedTxFromEvmTxRequest(t testing.TB, txStore txmgr.EvmTxStore, txRequest txmgr.TxRequest, chainID *big.Int) (tx txmgr.Tx) { - tx, err := txStore.CreateTransaction(txRequest, chainID) + tx, err := txStore.CreateTransaction(testutils.Context(t), txRequest, chainID) require.NoError(t, err) return tx } @@ -458,7 +458,7 @@ func MustInsertConfirmedEthTxBySaveFetchedReceipts(t *testing.T, txStore txmgr.T BlockNumber: big.NewInt(nonce), TransactionIndex: uint(1), } - err := txStore.SaveFetchedReceipts([]*evmtypes.Receipt{&receipt}, &chainID) + err := txStore.SaveFetchedReceipts(testutils.Context(t), []*evmtypes.Receipt{&receipt}, &chainID) require.NoError(t, err) return etx } @@ -472,75 +472,25 @@ func MustInsertFatalErrorEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, fromA return etx } -func MustAddRandomKeyToKeystore(t testing.TB, ethKeyStore keystore.Eth) (ethkey.KeyV2, common.Address) { - t.Helper() - - k := MustGenerateRandomKey(t) - MustAddKeyToKeystore(t, k, &FixtureChainID, ethKeyStore) - - return k, k.Address -} - -func MustAddRandomKeyToKeystoreWithChainID(t testing.TB, chainID *big.Int, ethKeyStore keystore.Eth) (ethkey.KeyV2, common.Address) { - t.Helper() - k := MustGenerateRandomKey(t) - MustAddKeyToKeystore(t, k, chainID, ethKeyStore) +type RandomKey struct { + Nonce int64 + Disabled bool - return k, k.Address + chainIDs []utils.Big // nil: Fixture, set empty for none } -func MustAddKeyToKeystore(t testing.TB, key ethkey.KeyV2, chainID *big.Int, ethKeyStore keystore.Eth) { - t.Helper() - ethKeyStore.XXXTestingOnlyAdd(key) - require.NoError(t, ethKeyStore.Add(key.Address, chainID)) - require.NoError(t, ethKeyStore.Enable(key.Address, chainID)) -} - -// MustInsertRandomKey inserts a randomly generated (not cryptographically -// secure) key for testing -// By default it is enabled for the fixture chain -func MustInsertRandomKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.KeyV2, common.Address) { - t.Helper() - - chainIDs := []utils.Big{*utils.NewBig(&FixtureChainID)} - for _, opt := range opts { - switch v := opt.(type) { - case utils.Big: - chainIDs[0] = v - case []utils.Big: - chainIDs = v - } +func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { + if r.chainIDs == nil { + r.chainIDs = []utils.Big{*utils.NewBig(&FixtureChainID)} } key := MustGenerateRandomKey(t) keystore.XXXTestingOnlyAdd(key) - for _, cid := range chainIDs { - var nonce int64 - enabled := true - for _, opt := range opts { - switch v := opt.(type) { - case int: - nonce = int64(v) - case int64: - nonce = v - case evmtypes.Nonce: - nonce = v.Int64() - case bool: - enabled = v - default: - t.Logf("ignoring unknown type in MustInsertRandomKey: %T, note: chain IDs are processed earlier", opt) - } - } + for _, cid := range r.chainIDs { require.NoError(t, keystore.Add(key.Address, cid.ToInt())) require.NoError(t, keystore.Enable(key.Address, cid.ToInt())) - err := keystore.Reset(key.Address, cid.ToInt(), nonce) - require.NoError(t, err) - if !enabled { + if r.Disabled { require.NoError(t, keystore.Disable(key.Address, cid.ToInt())) } } @@ -548,29 +498,29 @@ func MustInsertRandomKey( return key, key.Address } -func MustInsertRandomEnabledKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.KeyV2, common.Address) { - return MustInsertRandomKey(t, keystore, append(opts, true)) +func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { + k, address := r.MustInsert(t, keystore) + state := MustGetStateForKey(t, keystore, k) + return state, address +} + +// MustInsertRandomKey inserts a randomly generated (not cryptographically secure) key for testing. +// By default, it is enabled for the fixture chain. Pass chainIDs to override. +// Use MustInsertRandomKeyNoChains for a key associate with no chains. +func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils.Big) (ethkey.KeyV2, common.Address) { + r := RandomKey{} + if len(chainIDs) > 0 { + r.chainIDs = chainIDs + } + return r.MustInsert(t, keystore) } -func MustInsertRandomDisabledKey( - t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (key ethkey.KeyV2, address common.Address) { - return MustInsertRandomKey(t, keystore, append(opts, false)) +func MustInsertRandomKeyNoChains(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { + return RandomKey{chainIDs: []utils.Big{}}.MustInsert(t, keystore) } -func MustInsertRandomKeyReturningState(t testing.TB, - keystore keystore.Eth, - opts ...interface{}, -) (ethkey.State, common.Address) { - k, address := MustInsertRandomKey(t, keystore, opts...) - state := MustGetStateForKey(t, keystore, k) - return state, address +func MustInsertRandomKeyReturningState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { + return RandomKey{}.MustInsertWithState(t, keystore) } func MustGenerateRandomKey(t testing.TB) ethkey.KeyV2 { @@ -579,7 +529,7 @@ func MustGenerateRandomKey(t testing.TB) ethkey.KeyV2 { return key } -func MustGenerateRandomKeyState(t testing.TB) ethkey.State { +func MustGenerateRandomKeyState(_ testing.TB) ethkey.State { return ethkey.State{Address: NewEIP55Address()} } @@ -676,7 +626,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey } func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKeyStore keystore.Eth, keeperIndex, numKeepers, blockCountPerTurn int32) (keeper.Registry, job.Job) { - key, _ := MustAddRandomKeyToKeystoreWithChainID(t, testutils.SimulatedChainID, ethKeyStore) + key, _ := MustInsertRandomKey(t, ethKeyStore, *utils.NewBig(testutils.SimulatedChainID)) from := key.EIP55Address t.Helper() contractAddress := NewEIP55Address() diff --git a/core/internal/cltest/heavyweight/orm.go b/core/internal/cltest/heavyweight/orm.go index 3690a986e2e..841901c25aa 100644 --- a/core/internal/cltest/heavyweight/orm.go +++ b/core/internal/cltest/heavyweight/orm.go @@ -29,21 +29,21 @@ import ( // FullTestDBV2 creates a pristine DB which runs in a separate database than the normal // unit tests, so you can do things like use other Postgres connection types with it. -func FullTestDBV2(t *testing.T, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func FullTestDBV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { return prepareFullTestDBV2(t, name, false, true, overrideFn) } // FullTestDBNoFixturesV2 is the same as FullTestDB, but it does not load fixtures. -func FullTestDBNoFixturesV2(t *testing.T, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func FullTestDBNoFixturesV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { return prepareFullTestDBV2(t, name, false, false, overrideFn) } // FullTestDBEmptyV2 creates an empty DB (without migrations). -func FullTestDBEmptyV2(t *testing.T, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func FullTestDBEmptyV2(t testing.TB, name string, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { return prepareFullTestDBV2(t, name, true, false, overrideFn) } -func prepareFullTestDBV2(t *testing.T, name string, empty bool, loadFixtures bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { +func prepareFullTestDBV2(t testing.TB, name string, empty bool, loadFixtures bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { testutils.SkipShort(t, "FullTestDB") if empty && loadFixtures { diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 439ca2b721d..9fdbcbb373d 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -27,6 +27,7 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/robfig/cron/v3" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // MockSubscription a mock subscription @@ -308,35 +309,16 @@ func MustRandomUser(t testing.TB) sessions.User { return r } -// CreateUserWithRole inserts a new user with specified role and associated test DB email into the test DB -func CreateUserWithRole(t testing.TB, role sessions.UserRole) sessions.User { - email := "" - switch role { - case sessions.UserRoleAdmin: - email = APIEmailAdmin - case sessions.UserRoleEdit: - email = APIEmailEdit - case sessions.UserRoleRun: - email = APIEmailRun - case sessions.UserRoleView: - email = APIEmailViewOnly - default: - t.Fatal("Unexpected role for CreateUserWithRole") - } - - r, err := sessions.NewUser(email, Password, role) - if err != nil { - logger.TestLogger(t).Panic(err) - } - return r -} +func NewUserWithSession(t testing.TB, orm sessions.ORM) sessions.User { + u := MustRandomUser(t) + require.NoError(t, orm.CreateUser(&u)) -func MustNewUser(t *testing.T, email, password string) sessions.User { - r, err := sessions.NewUser(email, password, sessions.UserRoleAdmin) - if err != nil { - t.Fatal(err) - } - return r + _, err := orm.CreateSession(sessions.SessionRequest{ + Email: u.Email, + Password: Password, + }) + require.NoError(t, err) + return u } type MockAPIInitializer struct { diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 39eee3f7b43..c5d16590d52 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -3,6 +3,7 @@ package features_test import ( "bytes" "context" + _ "embed" "encoding/json" "fmt" "io" @@ -24,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/rpc" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -61,8 +63,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -263,15 +265,16 @@ func TestIntegration_AuthToken(t *testing.T) { // set up user mockUser := cltest.MustRandomUser(t) - apiToken := auth.Token{AccessKey: cltest.APIKey, Secret: cltest.APISecret} + key, secret := uuid.New().String(), uuid.New().String() + apiToken := auth.Token{AccessKey: key, Secret: secret} orm := app.SessionORM() require.NoError(t, orm.CreateUser(&mockUser)) require.NoError(t, orm.SetAuthToken(&mockUser, &apiToken)) url := app.Server.URL + "/users" headers := make(map[string]string) - headers[webauth.APIKey] = cltest.APIKey - headers[webauth.APISecret] = cltest.APISecret + headers[webauth.APIKey] = key + headers[webauth.APISecret] = secret resp, cleanup := cltest.UnauthenticatedGet(t, url, headers) defer cleanup() @@ -336,6 +339,12 @@ func setupOperatorContracts(t *testing.T) OperatorContracts { } } +//go:embed singleword-spec-template.yml +var singleWordSpecTemplate string + +//go:embed multiword-spec-template.yml +var multiWordSpecTemplate string + // Tests both single and multiple word responses - // i.e. both fulfillOracleRequest2 and fulfillOracleRequest. func TestIntegration_DirectRequest(t *testing.T) { @@ -351,7 +360,6 @@ func TestIntegration_DirectRequest(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { - t.Parallel() // Simulate a consumer contract calling to obtain ETH quotes in 3 different currencies // in a single callback. config := configtest2.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -387,9 +395,9 @@ func TestIntegration_DirectRequest(t *testing.T) { mockServerEUR := cltest.NewHTTPMockServer(t, 200, "GET", `{"EUR": 507.07}`) mockServerJPY := cltest.NewHTTPMockServer(t, 200, "GET", `{"JPY": 63818.86}`) - spec := string(cltest.MustReadFile(t, "../../testdata/tomlspecs/multiword-response-spec.toml")) - spec = strings.ReplaceAll(spec, "0x613a38AC1659769640aaE063C651F48E0250454C", operatorContracts.operatorAddress.Hex()) - spec = strings.ReplaceAll(spec, "example", "example 1") // make the name unique + nameAndExternalJobID := uuid.New() + addr := operatorContracts.operatorAddress.Hex() + spec := fmt.Sprintf(multiWordSpecTemplate, nameAndExternalJobID, addr, nameAndExternalJobID, addr) j := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: spec}))) cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, 5*time.Second) @@ -425,10 +433,8 @@ func TestIntegration_DirectRequest(t *testing.T) { cltest.AssertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) assertPricesUint256(t, big.NewInt(61464), big.NewInt(50707), big.NewInt(6381886), operatorContracts.multiWord) - // Do a single word request - singleWordSpec := string(cltest.MustReadFile(t, "../../testdata/tomlspecs/direct-request-spec-cbor.toml")) - singleWordSpec = strings.ReplaceAll(singleWordSpec, "0x613a38AC1659769640aaE063C651F48E0250454C", operatorContracts.operatorAddress.Hex()) - singleWordSpec = strings.ReplaceAll(singleWordSpec, "example", "example 2") // make the name unique + nameAndExternalJobID = uuid.New() + singleWordSpec := fmt.Sprintf(singleWordSpecTemplate, nameAndExternalJobID, addr, nameAndExternalJobID, addr) jobSingleWord := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: singleWordSpec}))) cltest.AwaitJobActive(t, app.JobSpawner(), jobSingleWord.ID, 5*time.Second) @@ -673,9 +679,8 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, dbName string, b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), ) (*cltest.TestApplication, string, common.Address, ocrkey.KeyV2) { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, portV1), func(c *chainlink.Config, s *chainlink.Secrets) { + p2pKey := keystest.NewP2PKeyV2(t) + config, _ := heavyweight.FullTestDBV2(t, dbName, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.OCR.Enabled = ptr(true) @@ -755,9 +760,8 @@ func setupForwarderEnabledNode( common.Address, ocrkey.KeyV2, ) { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, portV1), func(c *chainlink.Config, s *chainlink.Secrets) { + p2pKey := keystest.NewP2PKeyV2(t) + config, _ := heavyweight.FullTestDBV2(t, dbName, func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. c.OCR.Enabled = ptr(true) @@ -856,8 +860,9 @@ func TestIntegration_OCR(t *testing.T) { for _, tt := range tests { test := tt t.Run(test.name, func(t *testing.T) { - bootstrapNodePortV1 := test.portStart - bootstrapNodePortV2 := test.portStart + numOracles + 1 + t.Parallel() + bootstrapNodePortV1 := freeport.GetOne(t) + bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) @@ -870,9 +875,10 @@ func TestIntegration_OCR(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) + ports := freeport.GetN(t, 2*numOracles) for i := 0; i < numOracles; i++ { - portV1 := bootstrapNodePortV1 + i + 1 - portV2 := bootstrapNodePortV2 + i + 1 + portV1 := ports[2*i] + portV2 := ports[2*i+1] app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, test.id), b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) @@ -891,10 +897,10 @@ func TestIntegration_OCR(t *testing.T) { OracleIdentity: confighelper.OracleIdentity{ OnChainSigningAddress: ocrtypes.OnChainSigningAddress(key.OnChainSigning.Address()), TransmitAddress: transmitter, - OffchainPublicKey: ocrtypes.OffchainPublicKey(key.PublicKeyOffChain()), + OffchainPublicKey: key.PublicKeyOffChain(), PeerID: peerID, }, - SharedSecretEncryptionPublicKey: ocrtypes.SharedSecretEncryptionPublicKey(key.PublicKeyConfig()), + SharedSecretEncryptionPublicKey: key.PublicKeyConfig(), }) } @@ -1080,8 +1086,8 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { t.Parallel() numOracles := 4 t.Run("ocr_forwarder_flow", func(t *testing.T) { - bootstrapNodePortV1 := 20000 - bootstrapNodePortV2 := 20000 + numOracles + 1 + bootstrapNodePortV1 := freeport.GetOne(t) + bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) @@ -1096,9 +1102,10 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) + ports := freeport.GetN(t, 2*numOracles) for i := 0; i < numOracles; i++ { - portV1 := bootstrapNodePortV1 + i + 1 - portV2 := bootstrapNodePortV2 + i + 1 + portV1 := ports[2*i] + portV2 := ports[2*i+1] app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, fmt.Sprintf("o%d_%d", i, 1), b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) @@ -1117,10 +1124,10 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { OracleIdentity: confighelper.OracleIdentity{ OnChainSigningAddress: ocrtypes.OnChainSigningAddress(key.OnChainSigning.Address()), TransmitAddress: forwarder, - OffchainPublicKey: ocrtypes.OffchainPublicKey(key.PublicKeyOffChain()), + OffchainPublicKey: key.PublicKeyOffChain(), PeerID: peerID, }, - SharedSecretEncryptionPublicKey: ocrtypes.SharedSecretEncryptionPublicKey(key.PublicKeyConfig()), + SharedSecretEncryptionPublicKey: key.PublicKeyConfig(), }) } diff --git a/core/testdata/tomlspecs/multiword-response-spec.toml b/core/internal/features/multiword-spec-template.yml similarity index 88% rename from core/testdata/tomlspecs/multiword-response-spec.toml rename to core/internal/features/multiword-spec-template.yml index 31da76b797c..8479212f7d4 100644 --- a/core/testdata/tomlspecs/multiword-response-spec.toml +++ b/core/internal/features/multiword-spec-template.yml @@ -1,41 +1,34 @@ type = "directrequest" schemaVersion = 1 -name = "example eth request event spec" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -evmChainID = "1337" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" +name = "%s" +contractAddress = "%s" +evmChainID = 1337 +externalJobID = "%s" observationSource = """ decode_log [type=ethabidecodelog abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] decode_cbor [type=cborparse data="$(decode_log.data)"] - decode_log -> decode_cbor - decode_cbor -> usd decode_cbor -> eur decode_cbor -> jpy - usd [type=http method=GET url="$(decode_cbor.urlUSD)" allowunrestrictednetworkaccess="true"] usd_parse [type=jsonparse path="$(decode_cbor.pathUSD)"] usd_multiply [type=multiply value="$(usd_parse)", times="100"] usd -> usd_parse -> usd_multiply - eur [type=http method=GET url="$(decode_cbor.urlEUR)" allowunrestrictednetworkaccess="true"] eur_parse [type=jsonparse path="$(decode_cbor.pathEUR)"] eur_multiply [type=multiply value="$(eur_parse)", times="100"] eur -> eur_parse -> eur_multiply - jpy [type=http method=GET url="$(decode_cbor.urlJPY)" allowunrestrictednetworkaccess="true"] jpy_parse [type=jsonparse path="$(decode_cbor.pathJPY)"] jpy_multiply [type=multiply value="$(jpy_parse)", times="100"] jpy -> jpy_parse -> jpy_multiply - usd_multiply -> encode_mwr eur_multiply -> encode_mwr jpy_multiply -> encode_mwr - encode_mwr [type=ethabiencode abi="(bytes32 requestId, uint256 usd, uint256 eur, uint256 jpy)" data=<{ @@ -51,7 +44,6 @@ observationSource = """ "callbackFunctionId": $(decode_log.callbackFunctionId), "expiration": $(decode_log.cancelExpiration), "data": $(encode_mwr)}>] - submit_tx [type=ethtx to="0x613a38AC1659769640aaE063C651F48E0250454C" data="$(encode_tx)" minConfirmations="2"] - + submit_tx [type=ethtx to="%s" data="$(encode_tx)" minConfirmations="2"] encode_mwr -> encode_tx -> submit_tx """ diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 3883e0319ed..25b6781c4e9 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "maps" "math/big" "net/http" "net/http/httptest" @@ -21,12 +22,13 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "golang.org/x/exp/maps" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" @@ -42,8 +44,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" @@ -102,14 +104,13 @@ func setupOCR2Contracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBa func setupNodeOCR2( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, useForwarder bool, b *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) + p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -161,19 +162,19 @@ func setupNodeOCR2( if useForwarder { // deploy a forwarder - faddr, _, authorizedForwarder, err := authorized_forwarder.DeployAuthorizedForwarder(owner, b, common.HexToAddress("0x326C977E6efc84E512bB9C30f76E30c160eD06FB"), owner.From, common.Address{}, []byte{}) - require.NoError(t, err) + faddr, _, authorizedForwarder, err2 := authorized_forwarder.DeployAuthorizedForwarder(owner, b, common.HexToAddress("0x326C977E6efc84E512bB9C30f76E30c160eD06FB"), owner.From, common.Address{}, []byte{}) + require.NoError(t, err2) // set EOA as an authorized sender for the forwarder - _, err = authorizedForwarder.SetAuthorizedSenders(owner, []common.Address{transmitter}) - require.NoError(t, err) + _, err2 = authorizedForwarder.SetAuthorizedSenders(owner, []common.Address{transmitter}) + require.NoError(t, err2) b.Commit() // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) chainID := utils.Big(*b.Blockchain().Config().ChainID) - _, err = forwarderORM.CreateForwarder(faddr, chainID) - require.NoError(t, err) + _, err2 = forwarderORM.CreateForwarder(faddr, chainID) + require.NoError(t, err2) effectiveTransmitter = faddr } @@ -191,9 +192,7 @@ func TestIntegration_OCR2(t *testing.T) { owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) lggr := logger.TestLogger(t) - // Note it's plausible these ports could be occupied on a CI machine. - // May need a port randomize + retry approach if we observe collisions. - bootstrapNodePort := uint16(29999) + bootstrapNodePort := freeport.GetOne(t) bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", false /* useForwarders */, b, nil) var ( @@ -202,8 +201,9 @@ func TestIntegration_OCR2(t *testing.T) { kbs []ocr2key.KeyBundle apps []*cltest.TestApplication ) - for i := uint16(0); i < 4; i++ { - node := setupNodeOCR2(t, owner, bootstrapNodePort+1+i, fmt.Sprintf("oracle%d", i), false /* useForwarders */, b, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), false /* useForwarders */, b, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }) @@ -231,54 +231,8 @@ func TestIntegration_OCR2(t *testing.T) { } }() - lggr.Debugw("Setting Payees on OraclePlugin Contract", "transmitters", transmitters) - _, err := ocrContract.SetPayees( - owner, - transmitters, - transmitters, - ) - require.NoError(t, err) - blockBeforeConfig, err := b.BlockByNumber(testutils.Context(t), nil) - require.NoError(t, err) - signers, transmitters, threshold, _, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( - oracles, - 1, - 1000000000/100, // threshold PPB - ) - require.NoError(t, err) - - minAnswer, maxAnswer := new(big.Int), new(big.Int) - minAnswer.Exp(big.NewInt(-2), big.NewInt(191), nil) - maxAnswer.Exp(big.NewInt(2), big.NewInt(191), nil) - maxAnswer.Sub(maxAnswer, big.NewInt(1)) - - onchainConfig, err := testhelpers.GenerateDefaultOCR2OnchainConfig(minAnswer, maxAnswer) - require.NoError(t, err) - lggr.Debugw("Setting Config on Oracle Contract", - "signers", signers, - "transmitters", transmitters, - "threshold", threshold, - "onchainConfig", onchainConfig, - "encodedConfigVersion", encodedConfigVersion, - ) - _, err = ocrContract.SetConfig( - owner, - signers, - transmitters, - threshold, - onchainConfig, - encodedConfigVersion, - encodedConfig, - ) - require.NoError(t, err) - b.Commit() - - err = bootstrapNode.app.Start(testutils.Context(t)) - require.NoError(t, err) - - emvChains := bootstrapNode.app.GetRelayers().LegacyEVMChains() - require.NotNil(t, emvChains) - ocrJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(fmt.Sprintf(` + blockBeforeConfig := initOCR2(t, lggr, b, ocrContract, owner, bootstrapNode, oracles, transmitters, transmitters, func(blockNum int64) string { + return fmt.Sprintf(` type = "bootstrap" name = "bootstrap" relay = "evm" @@ -287,10 +241,8 @@ contractID = "%s" [relayConfig] chainID = 1337 fromBlock = %d -`, ocrContractAddress, blockBeforeConfig.Number().Int64())) - require.NoError(t, err) - err = bootstrapNode.app.AddJobV2(testutils.Context(t), &ocrJob) - require.NoError(t, err) +`, ocrContractAddress, blockNum) + }) var jids []int32 var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) @@ -306,8 +258,7 @@ fromBlock = %d } for i := 0; i < 4; i++ { s := i - err = apps[i].Start(testutils.Context(t)) - require.NoError(t, err) + require.NoError(t, apps[i].Start(testutils.Context(t))) // API speed is > observation timeout set in ContractSetConfigArgsForIntegrationTest slowServers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { @@ -316,9 +267,7 @@ fromBlock = %d _, err := res.Write([]byte(`{"data":10}`)) require.NoError(t, err) })) - t.Cleanup(func() { - slowServers[s].Close() - }) + t.Cleanup(slowServers[s].Close) servers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { b, err := io.ReadAll(req.Body) require.NoError(t, err) @@ -333,9 +282,7 @@ fromBlock = %d _, err = res.Write([]byte(`{"data":10}`)) require.NoError(t, err) })) - t.Cleanup(func() { - servers[s].Close() - }) + t.Cleanup(servers[s].Close) u, _ := url.Parse(servers[i].URL) require.NoError(t, apps[i].BridgeORM().CreateBridgeType(&bridges.BridgeType{ Name: bridges.BridgeName(fmt.Sprintf("bridge%d", i)), @@ -457,64 +404,25 @@ juelsPerFeeCoinSource = """ assert.Equal(t, digestAndEpoch.Epoch, epoch) } -func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { - t.Parallel() - owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) - - lggr := logger.TestLogger(t) - // Note it's plausible these ports could be occupied on a CI machine. - // May need a port randomize + retry approach if we observe collisions. - bootstrapNodePort := uint16(29898) - bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", true /* useForwarders */, b, nil) - - var ( - oracles []confighelper2.OracleIdentityExtra - transmitters []common.Address - forwarderContracts []common.Address - kbs []ocr2key.KeyBundle - apps []*cltest.TestApplication - ) - for i := uint16(0); i < 4; i++ { - node := setupNodeOCR2(t, owner, bootstrapNodePort+1+i, fmt.Sprintf("oracle%d", i), true /* useForwarders */, b, []commontypes.BootstrapperLocator{ - // Supply the bootstrap IP and port as a V2 peer address - {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }) - - // Effective transmitter should be a forwarder not an EOA. - require.NotEqual(t, node.effectiveTransmitter, node.transmitter) - - kbs = append(kbs, node.keybundle) - apps = append(apps, node.app) - forwarderContracts = append(forwarderContracts, node.effectiveTransmitter) - transmitters = append(transmitters, node.transmitter) - - oracles = append(oracles, confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: node.keybundle.PublicKey(), - TransmitAccount: ocrtypes2.Account(node.effectiveTransmitter.String()), - OffchainPublicKey: node.keybundle.OffchainPublicKey(), - PeerID: node.peerID, - }, - ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), - }) - } - - tick := time.NewTicker(1 * time.Second) - defer tick.Stop() - go func() { - for range tick.C { - b.Commit() - } - }() - - lggr.Debugw("Setting Payees on OraclePlugin Contract", "transmitters", forwarderContracts) +func initOCR2(t *testing.T, lggr logger.Logger, b *backends.SimulatedBackend, + ocrContract *ocr2aggregator.OCR2Aggregator, + owner *bind.TransactOpts, + bootstrapNode *ocr2Node, + oracles []confighelper2.OracleIdentityExtra, + transmitters []common.Address, + payees []common.Address, + specFn func(int64) string, +) ( + blockBeforeConfig *types.Block, +) { + lggr.Debugw("Setting Payees on OraclePlugin Contract", "transmitters", payees) _, err := ocrContract.SetPayees( owner, - forwarderContracts, transmitters, + payees, ) require.NoError(t, err) - blockBeforeConfig, err := b.BlockByNumber(testutils.Context(t), nil) + blockBeforeConfig, err = b.BlockByNumber(testutils.Context(t), nil) require.NoError(t, err) signers, effectiveTransmitters, threshold, _, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( oracles, @@ -556,7 +464,64 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { chainSet := bootstrapNode.app.GetRelayers().LegacyEVMChains() require.NotNil(t, chainSet) - ocrJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(fmt.Sprintf(` + ocrJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(specFn(blockBeforeConfig.Number().Int64())) + require.NoError(t, err) + err = bootstrapNode.app.AddJobV2(testutils.Context(t), &ocrJob) + require.NoError(t, err) + return +} + +func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { + t.Parallel() + owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) + + lggr := logger.TestLogger(t) + bootstrapNodePort := freeport.GetOne(t) + bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, "bootstrap", true /* useForwarders */, b, nil) + + var ( + oracles []confighelper2.OracleIdentityExtra + transmitters []common.Address + forwarderContracts []common.Address + kbs []ocr2key.KeyBundle + apps []*cltest.TestApplication + ) + ports := freeport.GetN(t, 4) + for i := uint16(0); i < 4; i++ { + node := setupNodeOCR2(t, owner, ports[i], fmt.Sprintf("oracle%d", i), true /* useForwarders */, b, []commontypes.BootstrapperLocator{ + // Supply the bootstrap IP and port as a V2 peer address + {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, + }) + + // Effective transmitter should be a forwarder not an EOA. + require.NotEqual(t, node.effectiveTransmitter, node.transmitter) + + kbs = append(kbs, node.keybundle) + apps = append(apps, node.app) + forwarderContracts = append(forwarderContracts, node.effectiveTransmitter) + transmitters = append(transmitters, node.transmitter) + + oracles = append(oracles, confighelper2.OracleIdentityExtra{ + OracleIdentity: confighelper2.OracleIdentity{ + OnchainPublicKey: node.keybundle.PublicKey(), + TransmitAccount: ocrtypes2.Account(node.effectiveTransmitter.String()), + OffchainPublicKey: node.keybundle.OffchainPublicKey(), + PeerID: node.peerID, + }, + ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), + }) + } + + tick := time.NewTicker(1 * time.Second) + defer tick.Stop() + go func() { + for range tick.C { + b.Commit() + } + }() + + blockBeforeConfig := initOCR2(t, lggr, b, ocrContract, owner, bootstrapNode, oracles, forwarderContracts, transmitters, func(int64) string { + return fmt.Sprintf(` type = "bootstrap" name = "bootstrap" relay = "evm" @@ -565,10 +530,8 @@ forwardingAllowed = true contractID = "%s" [relayConfig] chainID = 1337 -`, ocrContractAddress)) - require.NoError(t, err) - err = bootstrapNode.app.AddJobV2(testutils.Context(t), &ocrJob) - require.NoError(t, err) +`, ocrContractAddress) + }) var jids []int32 var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) @@ -584,8 +547,7 @@ chainID = 1337 } for i := 0; i < 4; i++ { s := i - err = apps[i].Start(testutils.Context(t)) - require.NoError(t, err) + require.NoError(t, apps[i].Start(testutils.Context(t))) // API speed is > observation timeout set in ContractSetConfigArgsForIntegrationTest slowServers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { diff --git a/core/testdata/tomlspecs/direct-request-spec-cbor.toml b/core/internal/features/singleword-spec-template.yml similarity index 83% rename from core/testdata/tomlspecs/direct-request-spec-cbor.toml rename to core/internal/features/singleword-spec-template.yml index 500c4973d88..4ceef574d91 100644 --- a/core/testdata/tomlspecs/direct-request-spec-cbor.toml +++ b/core/internal/features/singleword-spec-template.yml @@ -1,8 +1,8 @@ type = "directrequest" schemaVersion = 1 -name = "example eth request event spec" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F90" +name = "%s" +contractAddress = "%s" +externalJobID = "%s" evmChainID = 1337 observationSource = """ decode_log [type=ethabidecodelog @@ -22,6 +22,6 @@ observationSource = """ "callbackFunctionId": $(decode_log.callbackFunctionId), "expiration": $(decode_log.cancelExpiration), "data": $(encode_data)}>] - submit [type=ethtx to="0x613a38AC1659769640aaE063C651F48E0250454C" data="$(encode_tx)" minConfirmations="2"] + submit [type=ethtx to="%s" data="$(encode_tx)" minConfirmations="2"] decode_log->decode_cbor->ds1 -> ds1_parse -> ds1_multiply->encode_data->encode_tx->submit; """ diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index fd065dc5dec..ec656509afd 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -23,8 +23,6 @@ import ( mock "github.com/stretchr/testify/mock" - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" plugins "github.com/smartcontractkit/chainlink/v2/plugins" @@ -143,22 +141,6 @@ func (_m *Application) GetConfig() chainlink.GeneralConfig { return r0 } -// GetEventBroadcaster provides a mock function with given fields: -func (_m *Application) GetEventBroadcaster() pg.EventBroadcaster { - ret := _m.Called() - - var r0 pg.EventBroadcaster - if rf, ok := ret.Get(0).(func() pg.EventBroadcaster); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(pg.EventBroadcaster) - } - } - - return r0 -} - // GetExternalInitiatorManager provides a mock function with given fields: func (_m *Application) GetExternalInitiatorManager() webhook.ExternalInitiatorManager { ret := _m.Called() @@ -536,13 +518,12 @@ func (_m *Application) WakeSessionReaper() { _m.Called() } -type mockConstructorTestingTNewApplication interface { +// NewApplication creates a new instance of Application. 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 NewApplication(t interface { mock.TestingT Cleanup(func()) -} - -// NewApplication creates a new instance of Application. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewApplication(t mockConstructorTestingTNewApplication) *Application { +}) *Application { mock := &Application{} mock.Mock.Test(t) diff --git a/core/internal/mocks/flags.go b/core/internal/mocks/flags.go index 73d2dd683a2..5b5aa812680 100644 --- a/core/internal/mocks/flags.go +++ b/core/internal/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -1176,13 +1176,12 @@ func (_m *Flags) WatchRemovedAccess(opts *bind.WatchOpts, sink chan<- *flags_wra return r0, r1 } -type mockConstructorTestingTNewFlags interface { +// NewFlags creates a new instance of Flags. 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 NewFlags(t interface { mock.TestingT Cleanup(func()) -} - -// NewFlags creates a new instance of Flags. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFlags(t mockConstructorTestingTNewFlags) *Flags { +}) *Flags { mock := &Flags{} mock.Mock.Test(t) diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go index 60f662f5894..e3da1b83dff 100644 --- a/core/internal/mocks/flux_aggregator.go +++ b/core/internal/mocks/flux_aggregator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -2048,13 +2048,12 @@ func (_m *FluxAggregator) WithdrawablePayment(opts *bind.CallOpts, _oracle commo return r0, r1 } -type mockConstructorTestingTNewFluxAggregator interface { +// NewFluxAggregator creates a new instance of FluxAggregator. 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 NewFluxAggregator(t interface { mock.TestingT Cleanup(func()) -} - -// NewFluxAggregator creates a new instance of FluxAggregator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFluxAggregator(t mockConstructorTestingTNewFluxAggregator) *FluxAggregator { +}) *FluxAggregator { mock := &FluxAggregator{} mock.Mock.Test(t) diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go index 6fd136bc44f..b2556a0bad4 100644 --- a/core/internal/mocks/prometheus_backend.go +++ b/core/internal/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -38,13 +38,12 @@ func (_m *PrometheusBackend) SetUnconfirmedTransactions(_a0 *big.Int, _a1 int64) _m.Called(_a0, _a1) } -type mockConstructorTestingTNewPrometheusBackend interface { +// NewPrometheusBackend creates a new instance of PrometheusBackend. 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 NewPrometheusBackend(t interface { mock.TestingT Cleanup(func()) -} - -// NewPrometheusBackend creates a new instance of PrometheusBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewPrometheusBackend(t mockConstructorTestingTNewPrometheusBackend) *PrometheusBackend { +}) *PrometheusBackend { mock := &PrometheusBackend{} mock.Mock.Test(t) diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 2a86101d0d8..3a08c815166 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -3,6 +3,7 @@ package evmtest import ( "fmt" "math/big" + "slices" "sync" "sync/atomic" "testing" @@ -12,7 +13,6 @@ import ( "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-relay/pkg/types" diff --git a/core/internal/testutils/pgtest/txdb.go b/core/internal/testutils/pgtest/txdb.go index 1e65b1797b7..598a5dddc55 100644 --- a/core/internal/testutils/pgtest/txdb.go +++ b/core/internal/testutils/pgtest/txdb.go @@ -71,6 +71,9 @@ func init() { var _ driver.Conn = &conn{} +var _ driver.Validator = &conn{} +var _ driver.SessionResetter = &conn{} + // txDriver is an sql driver which runs on single transaction // when the Close is called, transaction is rolled back type txDriver struct { @@ -98,7 +101,7 @@ func (d *txDriver) Open(dsn string) (driver.Conn, error) { if err != nil { return nil, err } - c = &conn{tx: tx, opened: 1} + c = &conn{tx: tx, opened: 1, dsn: dsn} c.removeSelf = func() error { return d.deleteConn(c) } @@ -147,8 +150,9 @@ func (c *conn) Begin() (driver.Tx, error) { } // Implement the "ConnBeginTx" interface -func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - // TODO: Fix context handling +func (c *conn) BeginTx(_ context.Context, opts driver.TxOptions) (driver.Tx, error) { + // Context is ignored, because single transaction is shared by all callers, thus caller should not be able to + // control it with local context return c.Begin() } @@ -176,6 +180,27 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, e return &stmt{st, c}, nil } +// IsValid is called prior to placing the connection into the +// connection pool by database/sql. The connection will be discarded if false is returned. +func (c *conn) IsValid() bool { + c.Lock() + defer c.Unlock() + return !c.closed +} + +func (c *conn) ResetSession(ctx context.Context) error { + // Ensure bad connections are reported: From database/sql/driver: + // If a connection is never returned to the connection pool but immediately reused, then + // ResetSession is called prior to reuse but IsValid is not called. + c.Lock() + defer c.Unlock() + if c.closed { + return driver.ErrBadConn + } + + return nil +} + // pgx returns nil func (c *conn) CheckNamedValue(nv *driver.NamedValue) error { return nil diff --git a/core/internal/testutils/pgtest/txdb_test.go b/core/internal/testutils/pgtest/txdb_test.go new file mode 100644 index 00000000000..71960c6150a --- /dev/null +++ b/core/internal/testutils/pgtest/txdb_test.go @@ -0,0 +1,48 @@ +package pgtest + +import ( + "context" + "testing" + "time" + + "github.com/google/uuid" + "github.com/smartcontractkit/sqlx" + "github.com/stretchr/testify/assert" +) + +func TestTxDBDriver(t *testing.T) { + db := NewSqlxDB(t) + dropTable := func() error { + _, err := db.Exec(`DROP TABLE IF EXISTS txdb_test`) + return err + } + // clean up, if previous tests failed + err := dropTable() + assert.NoError(t, err) + _, err = db.Exec(`CREATE TABLE txdb_test (id TEXT NOT NULL)`) + assert.NoError(t, err) + t.Cleanup(func() { + _ = dropTable() + }) + _, err = db.Exec(`INSERT INTO txdb_test VALUES ($1)`, uuid.New().String()) + assert.NoError(t, err) + ensureValuesPresent := func(t *testing.T, db *sqlx.DB) { + var ids []string + err = db.Select(&ids, `SELECT id from txdb_test`) + assert.NoError(t, err) + assert.Len(t, ids, 1) + } + + ensureValuesPresent(t, db) + t.Run("Cancel of tx's context does not trigger rollback of driver's tx", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + _, err := db.BeginTx(ctx, nil) + assert.NoError(t, err) + cancel() + // BeginTx spawns separate goroutine that rollbacks the tx and tries to close underlying connection, unless + // db driver says that connection is still active. + // This approach is not ideal, but there is no better way to wait for independent goroutine to complete + time.Sleep(time.Second * 10) + ensureValuesPresent(t, db) + }) +} diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index d50efcc799a..938d814b9eb 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -24,10 +24,11 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" "github.com/gorilla/websocket" - "github.com/smartcontractkit/sqlx" "github.com/tidwall/gjson" "go.uber.org/zap/zaptest/observer" + "github.com/smartcontractkit/sqlx" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" // NOTE: To avoid circular dependencies, this package MUST NOT import diff --git a/core/logger/logger_mock_test.go b/core/logger/logger_mock_test.go index 2dc0fbbb9d0..2b6dfcf3b22 100644 --- a/core/logger/logger_mock_test.go +++ b/core/logger/logger_mock_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package logger @@ -284,13 +284,12 @@ func (_m *MockLogger) With(args ...interface{}) Logger { return r0 } -type mockConstructorTestingTNewMockLogger interface { +// NewMockLogger creates a new instance of MockLogger. 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 NewMockLogger(t interface { mock.TestingT Cleanup(func()) -} - -// NewMockLogger creates a new instance of MockLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMockLogger(t mockConstructorTestingTNewMockLogger) *MockLogger { +}) *MockLogger { mock := &MockLogger{} mock.Mock.Test(t) diff --git a/core/logger/mocks/logger.go b/core/logger/mocks/logger.go index 24752c2b6b6..965bd57baaf 100644 --- a/core/logger/mocks/logger.go +++ b/core/logger/mocks/logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -286,13 +286,12 @@ func (_m *Logger) With(args ...interface{}) logger.Logger { return r0 } -type mockConstructorTestingTNewLogger interface { +// NewLogger creates a new instance of Logger. 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 NewLogger(t interface { mock.TestingT Cleanup(func()) -} - -// NewLogger creates a new instance of Logger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLogger(t mockConstructorTestingTNewLogger) *Logger { +}) *Logger { mock := &Logger{} mock.Mock.Test(t) diff --git a/core/logger/zap.go b/core/logger/zap.go index 328b157a2a7..c739a80d45a 100644 --- a/core/logger/zap.go +++ b/core/logger/zap.go @@ -13,7 +13,6 @@ var _ Logger = &zapLogger{} type zapLogger struct { *zap.SugaredLogger level zap.AtomicLevel - name string fields []interface{} callerSkip int } @@ -49,16 +48,8 @@ func copyFields(fields []interface{}, add ...interface{}) []interface{} { return f } -func joinName(old, new string) string { - if old == "" { - return new - } - return old + "." + new -} - func (l *zapLogger) Named(name string) Logger { newLogger := *l - newLogger.name = joinName(l.name, name) newLogger.SugaredLogger = l.SugaredLogger.Named(name) newLogger.Trace("Named logger created") return &newLogger @@ -72,7 +63,7 @@ func (l *zapLogger) Helper(skip int) Logger { } func (l *zapLogger) Name() string { - return l.name + return l.Desugar().Name() } func (l *zapLogger) sugaredHelper(skip int) *zap.SugaredLogger { diff --git a/core/logger/zap_disk_logging.go b/core/logger/zap_disk_logging.go index d4cb92212ab..bf27eb0bd79 100644 --- a/core/logger/zap_disk_logging.go +++ b/core/logger/zap_disk_logging.go @@ -119,21 +119,15 @@ func newRotatingFileLogger(zcfg zap.Config, c Config, cores ...zapcore.Core) (*z go lggr.pollDiskSpace() - var once sync.Once - closeLogger := func() error { - var innerErr error - once.Do(func() { - defer defaultCloseFn() - defer diskCloseFn() + closeLogger := sync.OnceValue(func() error { + defer defaultCloseFn() + defer diskCloseFn() - close(lggr.pollDiskSpaceStop) - <-lggr.pollDiskSpaceDone + close(lggr.pollDiskSpaceStop) + <-lggr.pollDiskSpaceDone - innerErr = lggr.Sync() - }) - - return innerErr - } + return lggr.Sync() + }) return lggr, closeLogger, err } diff --git a/core/scripts/chaincli/README.md b/core/scripts/chaincli/README.md index c4c48c899da..da7aa7cc777 100644 --- a/core/scripts/chaincli/README.md +++ b/core/scripts/chaincli/README.md @@ -2,7 +2,7 @@ Before starting, you will need: 1. A working [Go](https://go.dev/doc/install) installation -2. EVM chain endpoint URLs +2. EVM chain endpoint URLs - The endpoint can be a local node, or an externally hosted node, e.g. [alchemy](alchemy.com) or [infura](infura.io) - Both the HTTPS and WSS URLs of your endpoint are needed 3. The chain ID corresponding to your chain, you can find the chain ID for your chosen chain [here](https://chainlist.org/) @@ -10,12 +10,12 @@ Before starting, you will need: - Steps for exporting your private key from Metamask can be found [here](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-Export-an-Account-Private-Key) 5. The LINK address, LINK-ETH feed address, fast gas feed address for your chain 6. Install [docker](https://docs.docker.com/get-docker/) for CLI and GUI (optional) +7. \[Optional\] get a [tenderly API key](https://docs.tenderly.co/other/platform-access/how-to-generate-api-access-tokens) and find your [username / project name](https://docs.tenderly.co/other/platform-access/how-to-find-the-project-slug-username-and-organization-name). -The example .env in this repo is for the Polygon Mumbai testnet. You can use [this faucet](https://faucets.chain.link/mumbai) to send testnet LINK +The example .env in this repo is for the Polygon Mumbai testnet. You can use [this faucet](https://faucets.chain.link/mumbai) to send testnet LINK to your wallet ahead of executing the next steps ->Note: Be careful with your key. When using testnets, it's best to use a separate ->account that does not hold real funds. +>Note: Be careful with your key. When using testnets, it's best to use a separate account that does not hold real funds. ## Run OCR2Keepers locally @@ -121,4 +121,4 @@ You can use the `grep` and `grepv` flags to filter log lines, e.g. to only show ```shell ./chaincli keeper logs --grep keepers-plugin -``` \ No newline at end of file +``` diff --git a/core/scripts/chaincli/command/feed/deploy.go b/core/scripts/chaincli/command/feed/deploy.go deleted file mode 100644 index 7397c6154f4..00000000000 --- a/core/scripts/chaincli/command/feed/deploy.go +++ /dev/null @@ -1,21 +0,0 @@ -package feed - -import ( - "github.com/spf13/cobra" - - "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" - "github.com/smartcontractkit/chainlink/core/scripts/chaincli/handler" -) - -// deployCmd represents the command to run the service. -var deployCmd = &cobra.Command{ - Use: "deploy", - Short: "Deploy price feed", - Long: `This command deploys price feeds.`, - Run: func(cmd *cobra.Command, args []string) { - cfg := config.New() - hdlr := handler.NewFeed(cfg) - - hdlr.DeployDerivedPriceFeed(cmd.Context()) - }, -} diff --git a/core/scripts/chaincli/command/feed/root.go b/core/scripts/chaincli/command/feed/root.go deleted file mode 100644 index 89d93efcb9b..00000000000 --- a/core/scripts/chaincli/command/feed/root.go +++ /dev/null @@ -1,16 +0,0 @@ -package feed - -import ( - "github.com/spf13/cobra" -) - -// RootCmd represents the root price feed sub-command to manage feeds. -var RootCmd = &cobra.Command{ - Use: "feed", - Short: "Manage price feeds", - Long: `This command represents a CLI interface to manage Chainlink Price Feeds.`, -} - -func init() { - RootCmd.AddCommand(deployCmd) -} diff --git a/core/scripts/chaincli/command/keeper/debug.go b/core/scripts/chaincli/command/keeper/debug.go new file mode 100644 index 00000000000..455c04efe6d --- /dev/null +++ b/core/scripts/chaincli/command/keeper/debug.go @@ -0,0 +1,20 @@ +package keeper + +import ( + "github.com/spf13/cobra" + + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/handler" +) + +// jobCmd represents the command to run the service +var debugCmd = &cobra.Command{ + Use: "debug", + Short: "Debug an upkeep", + Long: `This command debugs an upkeep on the povided registry to figure out why it is not performing`, + Run: func(cmd *cobra.Command, args []string) { + cfg := config.New() + hdlr := handler.NewKeeper(cfg) + hdlr.Debug(cmd.Context(), args) + }, +} diff --git a/core/scripts/chaincli/command/keeper/root.go b/core/scripts/chaincli/command/keeper/root.go index 47cb2fc4300..e00052e3ebb 100644 --- a/core/scripts/chaincli/command/keeper/root.go +++ b/core/scripts/chaincli/command/keeper/root.go @@ -13,6 +13,7 @@ var RootCmd = &cobra.Command{ func init() { RootCmd.AddCommand(deployCmd) + RootCmd.AddCommand(debugCmd) RootCmd.AddCommand(jobCmd) RootCmd.AddCommand(logsCmd) RootCmd.AddCommand(registryCmd) diff --git a/core/scripts/chaincli/command/root.go b/core/scripts/chaincli/command/root.go index 8f5e10e74f3..06e6e61a47d 100644 --- a/core/scripts/chaincli/command/root.go +++ b/core/scripts/chaincli/command/root.go @@ -7,7 +7,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/smartcontractkit/chainlink/core/scripts/chaincli/command/feed" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/command/keeper" ) @@ -34,7 +33,6 @@ func init() { _ = viper.BindPFlag("config", RootCmd.PersistentFlags().Lookup("config")) RootCmd.AddCommand(keeper.RootCmd) - RootCmd.AddCommand(feed.RootCmd) RootCmd.AddCommand(BootstrapNodeCmd) RootCmd.AddCommand(RevertReasonCmd) } diff --git a/core/scripts/chaincli/config/config.go b/core/scripts/chaincli/config/config.go index 3f4809bf772..d227aa2e298 100644 --- a/core/scripts/chaincli/config/config.go +++ b/core/scripts/chaincli/config/config.go @@ -91,10 +91,16 @@ type Config struct { FeedDecimals uint8 `mapstructure:"FEED_DECIMALS"` // Mercury Config - MercuryURL string `mapstructure:"MERCURY_URL"` - MercuryID string `mapstructure:"MERCURY_ID"` - MercuryKey string `mapstructure:"MERCURY_KEY"` - MercuryCredName string `mapstructure:"MERCURY_CRED_NAME"` + MercuryURL string `mapstructure:"MERCURY_URL"` + MercuryLegacyURL string `mapstructure:"MERCURY_LEGACY_URL"` + MercuryID string `mapstructure:"MERCURY_ID"` + MercuryKey string `mapstructure:"MERCURY_KEY"` + MercuryCredName string `mapstructure:"MERCURY_CRED_NAME"` + + // Tenderly + TenderlyKey string `mapstructure:"TENDERLY_KEY"` + TenderlyAccountName string `mapstructure:"TENDERLY_ACCOUNT_NAME"` + TenderlyProjectName string `mapstructure:"TENDERLY_PROJECT_NAME"` } // New creates a new config diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go new file mode 100644 index 00000000000..bdbce799264 --- /dev/null +++ b/core/scripts/chaincli/handler/debug.go @@ -0,0 +1,473 @@ +package handler + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "log" + "math" + "math/big" + "net/http" + "os" + "strconv" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" + "github.com/smartcontractkit/chainlink/core/scripts/common" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/utils" + bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" +) + +const ( + ConditionTrigger uint8 = iota + LogTrigger + + blockNumber = "blockNumber" + expectedTypeAndVersion = "KeeperRegistry 2.1.0" + feedIdHex = "feedIdHex" + feedIDs = "feedIDs" + timestamp = "timestamp" +) + +var packer = encoding.NewAbiPacker() + +var links []string + +func (k *Keeper) Debug(ctx context.Context, args []string) { + if len(args) < 1 { + failCheckArgs("no upkeepID supplied", nil) + } + // test that we are connected to an archive node + _, err := k.client.BalanceAt(ctx, gethcommon.Address{}, big.NewInt(1)) + if err != nil { + failCheckConfig("you are not connected to an archive node; try using infura or alchemy", err) + } + chainIDBig, err := k.client.ChainID(ctx) + if err != nil { + failUnknown("unable to retrieve chainID from rpc client", err) + } + chainID := chainIDBig.Int64() + // connect to registry contract + latestCallOpts := &bind.CallOpts{Context: ctx} // always use latest block + triggerCallOpts := &bind.CallOpts{Context: ctx} // use latest block for conditionals, but use block from tx for log triggers + registryAddress := gethcommon.HexToAddress(k.cfg.RegistryAddress) + keeperRegistry21, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, k.client) + if err != nil { + failUnknown("failed to connect to registry contract", err) + } + // verify contract is correct + typeAndVersion, err := keeperRegistry21.TypeAndVersion(latestCallOpts) + if err != nil { + failCheckConfig("failed to get typeAndVersion: are you sure you have the correct contract address?", err) + } + if typeAndVersion != expectedTypeAndVersion { + failCheckConfig(fmt.Sprintf("invalid registry contract: this command can only debug %s, got: %s", expectedTypeAndVersion, typeAndVersion), nil) + } + // get upkeepID from command args + upkeepID := big.NewInt(0) + upkeepIDNoPrefix := utils.RemoveHexPrefix(args[0]) + _, wasBase10 := upkeepID.SetString(upkeepIDNoPrefix, 10) + if !wasBase10 { + _, wasBase16 := upkeepID.SetString(upkeepIDNoPrefix, 16) + if !wasBase16 { + failCheckArgs("invalid upkeep ID", nil) + } + } + // get upkeep info + triggerType, err := keeperRegistry21.GetTriggerType(latestCallOpts, upkeepID) + if err != nil { + failUnknown("failed to get trigger type: ", err) + } + upkeepInfo, err := keeperRegistry21.GetUpkeep(latestCallOpts, upkeepID) + if err != nil { + failUnknown("failed to get trigger type: ", err) + } + minBalance, err := keeperRegistry21.GetMinBalance(latestCallOpts, upkeepID) + if err != nil { + failUnknown("failed to get min balance: ", err) + } + // do basic sanity checks + if (upkeepInfo.Target == gethcommon.Address{}) { + failCheckArgs("this upkeep does not exist on this registry", nil) + } + addLink("upkeep", common.UpkeepLink(chainID, upkeepID)) + addLink("target", common.ContractExplorerLink(chainID, upkeepInfo.Target)) + if upkeepInfo.Paused { + resolveIneligible("upkeep is paused") + } + if upkeepInfo.MaxValidBlocknumber != math.MaxUint32 { + resolveIneligible("upkeep is cancelled") + } + message("upkeep is active (not paused or cancelled)") + if upkeepInfo.Balance.Cmp(minBalance) == -1 { + resolveIneligible("minBalance is < upkeep balance") + } + message("upkeep is funded above the min balance") + if bigmath.Div(bigmath.Mul(bigmath.Sub(upkeepInfo.Balance, minBalance), big.NewInt(100)), minBalance).Cmp(big.NewInt(5)) == -1 { + warning("upkeep balance is < 5% larger than minBalance") + } + // local state for pipeline results + var checkResult iregistry21.CheckUpkeep + var blockNum uint64 + var performData []byte + upkeepNeeded := false + // check upkeep + if triggerType == ConditionTrigger { + message("upkeep identified as conditional trigger") + tmpCheckResult, err := keeperRegistry21.CheckUpkeep0(latestCallOpts, upkeepID) + if err != nil { + failUnknown("failed to check upkeep: ", err) + } + checkResult = iregistry21.CheckUpkeep(tmpCheckResult) + // do tenderly simulation + rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, []byte{}) + if err != nil { + failUnknown("failed to pack raw checkUpkeep call", err) + } + addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, 0, rawCall, registryAddress)) + } else if triggerType == LogTrigger { + // validate inputs + message("upkeep identified as log trigger") + if len(args) != 3 { + failCheckArgs("txHash and log index must be supplied to command in order to debug log triggered upkeeps", nil) + } + txHash := gethcommon.HexToHash(args[1]) + logIndex, err := strconv.ParseInt(args[2], 10, 64) + if err != nil { + failCheckArgs("unable to parse log index", err) + } + // find transaciton receipt + _, isPending, err := k.client.TransactionByHash(ctx, txHash) + if err != nil { + log.Fatal("failed to fetch tx receipt", err) + } + if isPending { + resolveIneligible(fmt.Sprintf("tx %s is still pending confirmation", txHash)) + } + receipt, err := k.client.TransactionReceipt(ctx, txHash) + if err != nil { + failCheckArgs("failed to fetch tx receipt", err) + } + addLink("trigger", common.ExplorerLink(chainID, txHash)) + blockNum = receipt.BlockNumber.Uint64() + // find matching log event in tx + var triggeringEvent *types.Log + for i, log := range receipt.Logs { + if log.Index == uint(logIndex) { + triggeringEvent = receipt.Logs[i] + } + } + if triggeringEvent == nil { + failCheckArgs(fmt.Sprintf("unable to find log with index %d in transaction", logIndex), nil) + } + // check that tx for this upkeep / tx was not already performed + message(fmt.Sprintf("LogTrigger{blockNum: %d, blockHash: %s, txHash: %s, logIndex: %d}", blockNum, receipt.BlockHash.Hex(), txHash, logIndex)) + workID := mustUpkeepWorkID(upkeepID, blockNum, receipt.BlockHash, txHash, logIndex) + message(fmt.Sprintf("workID computed: %s", hex.EncodeToString(workID[:]))) + hasKey, err := keeperRegistry21.HasDedupKey(latestCallOpts, workID) + if err != nil { + failUnknown("failed to check if upkeep was already performed: ", err) + } + if hasKey { + resolveIneligible("upkeep was already performed") + } + triggerCallOpts = &bind.CallOpts{Context: ctx, BlockNumber: big.NewInt(receipt.BlockNumber.Int64())} + rawTriggerConfig, err := keeperRegistry21.GetUpkeepTriggerConfig(triggerCallOpts, upkeepID) + if err != nil { + failUnknown("failed to fetch trigger config for upkeep", err) + } + triggerConfig, err := packer.UnpackLogTriggerConfig(rawTriggerConfig) + if err != nil { + failUnknown("failed to unpack trigger config", err) + } + if triggerConfig.FilterSelector > 7 { + resolveIneligible(fmt.Sprintf("invalid filter selector %d", triggerConfig.FilterSelector)) + } + if !logMatchesTriggerConfig(triggeringEvent, triggerConfig) { + resolveIneligible("log does not match trigger config") + } + header, err := k.client.HeaderByHash(ctx, receipt.BlockHash) + if err != nil { + failUnknown("failed to find block", err) + } + triggerData, err := packTriggerData(triggeringEvent, header.Time) + if err != nil { + failUnknown("failed to pack trigger data", err) + } + checkResult, err = keeperRegistry21.CheckUpkeep(triggerCallOpts, upkeepID, triggerData) + if err != nil { + failUnknown("failed to check upkeep", err) + } + // do tenderly simulations + rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, triggerData) + if err != nil { + failUnknown("failed to pack raw checkUpkeep call", err) + } + addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + rawCall = append(core.ILogAutomationABI.Methods["checkLog"].ID, triggerData...) + addLink("checkLog (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) + } else { + resolveIneligible(fmt.Sprintf("invalid trigger type: %d", triggerType)) + } + upkeepNeeded, performData = checkResult.UpkeepNeeded, checkResult.PerformData + // handle streams lookup + if checkResult.UpkeepFailureReason != 0 { + message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + } + if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { + streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) + if err == nil { + message("upkeep reverted with StreamsLookup") + message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) + if streamsLookupErr.FeedParamKey == feedIdHex && streamsLookupErr.TimeParamKey == blockNumber { + message("using mercury lookup v0.2") + // handle v0.2 + cfg, err := keeperRegistry21.GetUpkeepPrivilegeConfig(triggerCallOpts, upkeepID) + if err != nil { + failUnknown("failed to get upkeep privilege config ", err) + } + allowed := false + if len(cfg) > 0 { + var privilegeConfig evm.UpkeepPrivilegeConfig + if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { + failUnknown("failed to unmarshal privilege config ", err) + } + allowed = privilegeConfig.MercuryEnabled + } + if !allowed { + resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") + } + } else if streamsLookupErr.FeedParamKey != feedIDs || streamsLookupErr.TimeParamKey != timestamp { + // handle v0.3 + resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") + } else { + message("using mercury lookup v0.3") + } + streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} + handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) + state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) + if failureReason == UpkeepFailureReasonInvalidRevertDataInput { + resolveIneligible("upkeep used invalid revert data") + } + if state == InvalidMercuryRequest { + resolveIneligible("the mercury request data is invalid") + } + if err != nil { + failCheckConfig("failed to do mercury request ", err) + } + callbackResult, err := keeperRegistry21.CheckCallback(triggerCallOpts, upkeepID, values, streamsLookup.extraData) + if err != nil { + failUnknown("failed to execute mercury callback ", err) + } + upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData + // do tenderly simulation + rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) + if err != nil { + failUnknown("failed to pack raw checkUpkeep call", err) + } + addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + } else { + message("did not revert with StreamsLookup error") + } + } + if !upkeepNeeded { + resolveIneligible("upkeep is not needed") + } + // simulate perform ukeep + simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(latestCallOpts, upkeepID, performData) + if err != nil { + failUnknown("failed to simulate perform upkeep: ", err) + } + if simulateResult.Success { + resolveEligible() + } +} + +func logMatchesTriggerConfig(log *types.Log, config automation_utils_2_1.LogTriggerConfig) bool { + if log.Topics[0] != config.Topic0 { + return false + } + if config.FilterSelector&1 > 0 && (len(log.Topics) < 1 || log.Topics[1] != config.Topic1) { + return false + } + if config.FilterSelector&2 > 0 && (len(log.Topics) < 2 || log.Topics[2] != config.Topic2) { + return false + } + if config.FilterSelector&4 > 0 && (len(log.Topics) < 3 || log.Topics[3] != config.Topic3) { + return false + } + return true +} + +func packTriggerData(log *types.Log, blockTime uint64) ([]byte, error) { + var topics [][32]byte + for _, topic := range log.Topics { + topics = append(topics, topic) + } + b, err := core.UtilsABI.Methods["_log"].Inputs.Pack(&automation_utils_2_1.Log{ + Index: big.NewInt(int64(log.Index)), + Timestamp: big.NewInt(int64(blockTime)), + TxHash: log.TxHash, + BlockNumber: big.NewInt(int64(log.BlockNumber)), + BlockHash: log.BlockHash, + Source: log.Address, + Topics: topics, + Data: log.Data, + }) + if err != nil { + return nil, err + } + return b, nil +} + +func mustUpkeepWorkID(upkeepID *big.Int, blockNum uint64, blockHash [32]byte, txHash [32]byte, logIndex int64) [32]byte { + // TODO - this is a copy of the code in core.UpkeepWorkID + // We should refactor that code to be more easily exported ex not rely on Trigger structs + trigger := ocr2keepers.Trigger{ + LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ + TxHash: txHash, + Index: uint32(logIndex), + BlockNumber: ocr2keepers.BlockNumber(blockNum), + BlockHash: blockHash, + }, + } + upkeepIdentifier := &ocr2keepers.UpkeepIdentifier{} + upkeepIdentifier.FromBigInt(upkeepID) + workID := core.UpkeepWorkID(*upkeepIdentifier, trigger) + workIDBytes, err := hex.DecodeString(workID) + if err != nil { + failUnknown("failed to decode workID", err) + } + var result [32]byte + copy(result[:], workIDBytes[:]) + return result +} + +func message(msg string) { + log.Printf("☑️ %s", msg) +} + +func warning(msg string) { + log.Printf("⚠️ %s", msg) +} + +func resolveIneligible(msg string) { + exit(fmt.Sprintf("✅ %s: this upkeep is not currently elligible", msg), nil, 0) +} + +func resolveEligible() { + exit("❌ this upkeep is currently elligible", nil, 0) +} + +func rerun(msg string, err error) { + exit(fmt.Sprintf("🔁 %s: rerun this command", msg), err, 1) +} + +func failUnknown(msg string, err error) { + exit(fmt.Sprintf("🤷 %s: this should not happen - this script may be broken or your RPC may be experiencing issues", msg), err, 1) +} + +func failCheckConfig(msg string, err error) { + rerun(fmt.Sprintf("%s: check your config", msg), err) +} + +func failCheckArgs(msg string, err error) { + rerun(fmt.Sprintf("%s: check your command arguments", msg), err) +} + +func addLink(identifier string, link string) { + links = append(links, fmt.Sprintf("🔗 %s: %s", identifier, link)) +} + +func printLinks() { + for i := 0; i < len(links); i++ { + log.Println(links[i]) + } +} + +func exit(msg string, err error, code int) { + if err != nil { + log.Printf("⚠️ %v", err) + } + log.Println(msg) + printLinks() + os.Exit(code) +} + +type TenderlyAPIResponse struct { + Simulation struct { + Id string + } +} + +func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, input []byte, contractAddress gethcommon.Address) string { + errResult := "" + if cfg.TenderlyAccountName == "" || cfg.TenderlyKey == "" || cfg.TenderlyProjectName == "" { + warning("tenderly credentials not properly configured - this is optional but helpful") + return errResult + } + values := map[string]interface{}{ + "network_id": fmt.Sprintf("%d", chainID), + "from": "0x0000000000000000000000000000000000000000", + "input": hexutil.Encode(input), + "to": contractAddress.Hex(), + "gas": 50_000_000, + "save": true, + } + if blockNumber > 0 { + values["block_number"] = blockNumber + } + jsonData, err := json.Marshal(values) + if err != nil { + warning(fmt.Sprintf("unable to marshal tenderly request data: %v", err)) + return errResult + } + request, err := http.NewRequest( + "POST", + fmt.Sprintf("https://api.tenderly.co/api/v1/account/%s/project/%s/simulate", cfg.TenderlyAccountName, cfg.TenderlyProjectName), + bytes.NewBuffer(jsonData), + ) + if err != nil { + warning(fmt.Sprintf("unable to create tenderly request: %v", err)) + return errResult + } + request.Header.Set("X-Access-Key", cfg.TenderlyKey) + request.Header.Set("Content-Type", "application/json") + client := &http.Client{} + response, err := client.Do(request) + if err != nil { + warning(fmt.Sprintf("could not run tenderly simulation: %v", err)) + return errResult + } + defer response.Body.Close() + body, err := io.ReadAll(response.Body) + if err != nil { + warning(fmt.Sprintf("unable to read response body from tenderly response: %v", err)) + return errResult + } + var responseJSON = &TenderlyAPIResponse{} + err = json.Unmarshal(body, responseJSON) + if err != nil { + warning(fmt.Sprintf("unable to unmarshal tenderly response: %v", err)) + return errResult + } + if responseJSON.Simulation.Id == "" { + warning("unable to simulate tenderly tx") + return errResult + } + return common.TenderlySimLink(responseJSON.Simulation.Id) +} + +// TODO - link to performUpkeep tx if exists diff --git a/core/scripts/chaincli/handler/feed.go b/core/scripts/chaincli/handler/feed.go deleted file mode 100644 index b8481d4a3fc..00000000000 --- a/core/scripts/chaincli/handler/feed.go +++ /dev/null @@ -1,55 +0,0 @@ -package handler - -import ( - "context" - "log" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" - feed "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/derived_price_feed_wrapper" -) - -// Feed is the price feeds commands handler -type Feed struct { - *baseHandler - - baseAddress common.Address - quoteAddress common.Address - decimals uint8 -} - -// NewFeed is the constructor of Feed -func NewFeed(cfg *config.Config) *Feed { - return &Feed{ - baseHandler: NewBaseHandler(cfg), - baseAddress: common.HexToAddress(cfg.FeedBaseAddr), - quoteAddress: common.HexToAddress(cfg.FeedQuoteAddr), - decimals: cfg.FeedDecimals, - } -} - -// DeployDerivedPriceFeed deploys and approves the derived price feed. -func (h *Feed) DeployDerivedPriceFeed(ctx context.Context) { - // Deploy derived price feed - log.Println("Deploying derived price feed...") - feedAddr, deployFeedTx, _, err := feed.DeployDerivedPriceFeed(h.buildTxOpts(ctx), h.client, - h.baseAddress, - h.quoteAddress, - h.decimals, - ) - if err != nil { - log.Fatal("DeployDerivedPriceFeed failed: ", err) - } - log.Println("Waiting for derived price feed contract deployment confirmation...", deployFeedTx.Hash().Hex()) - h.waitDeployment(ctx, deployFeedTx) - log.Println(feedAddr.Hex(), ": Derived price feed successfully deployed - ", deployFeedTx.Hash().Hex()) - - // Approve derived price feed - approveRegistryTx, err := h.linkToken.Approve(h.buildTxOpts(ctx), feedAddr, h.approveAmount) - if err != nil { - log.Fatal(feedAddr.Hex(), ": Approve failed - ", err) - } - h.waitTx(ctx, approveRegistryTx) - log.Println(feedAddr.Hex(), ": Derived price feed successfully approved - ", approveRegistryTx.Hash().Hex()) -} diff --git a/core/scripts/chaincli/handler/handler.go b/core/scripts/chaincli/handler/handler.go index b33748c00fa..f72e94605d4 100644 --- a/core/scripts/chaincli/handler/handler.go +++ b/core/scripts/chaincli/handler/handler.go @@ -64,9 +64,7 @@ HTTPSPort = 0 LogPoller = true [OCR2] Enabled = true -[P2P] -[P2P.V2] -Enabled = true + [Keeper] TurnLookBack = 0 [[EVM]] @@ -106,24 +104,30 @@ func NewBaseHandler(cfg *config.Config) *baseHandler { nodeClient := ethclient.NewClient(rpcClient) // Parse private key - d := new(big.Int).SetBytes(common.FromHex(cfg.PrivateKey)) - pkX, pkY := crypto.S256().ScalarBaseMult(d.Bytes()) - privateKey := &ecdsa.PrivateKey{ - PublicKey: ecdsa.PublicKey{ - Curve: crypto.S256(), - X: pkX, - Y: pkY, - }, - D: d, - } + var fromAddr common.Address + var privateKey *ecdsa.PrivateKey + if cfg.PrivateKey != "" { + d := new(big.Int).SetBytes(common.FromHex(cfg.PrivateKey)) + pkX, pkY := crypto.S256().ScalarBaseMult(d.Bytes()) + privateKey = &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: crypto.S256(), + X: pkX, + Y: pkY, + }, + D: d, + } - // Init from address - publicKey := privateKey.Public() - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - log.Fatal("error casting public key to ECDSA") + // Init from address + publicKey := privateKey.Public() + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + log.Fatal("error casting public key to ECDSA") + } + fromAddr = crypto.PubkeyToAddress(*publicKeyECDSA) + } else { + log.Println("WARNING: no PRIVATE_KEY set: cannot use commands that deploy contracts or send transactions") } - fromAddr := crypto.PubkeyToAddress(*publicKeyECDSA) // Create link token wrapper linkToken, err := link.NewLinkToken(common.HexToAddress(cfg.LinkTokenAddr), nodeClient) diff --git a/core/scripts/chaincli/handler/mercury_lookup_handler.go b/core/scripts/chaincli/handler/mercury_lookup_handler.go new file mode 100644 index 00000000000..0db142df9f9 --- /dev/null +++ b/core/scripts/chaincli/handler/mercury_lookup_handler.go @@ -0,0 +1,536 @@ +package handler + +import ( + "context" + "crypto/hmac" + "encoding/hex" + "fmt" + "io" + "math/big" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "crypto/sha256" + + "encoding/json" + + "github.com/avast/retry-go" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/pkg/errors" +) + +// MercuryLookupHandler is responsible for initiating the calls to the Mercury server +// to determine whether the upkeeps are eligible +type MercuryLookupHandler struct { + credentials *MercuryCredentials + httpClient HttpClient + rpcClient *rpc.Client +} + +func NewMercuryLookupHandler( + credentials *MercuryCredentials, + rpcClient *rpc.Client, +) *MercuryLookupHandler { + return &MercuryLookupHandler{ + credentials: credentials, + httpClient: http.DefaultClient, + rpcClient: rpcClient, + } +} + +type MercuryVersion string + +type StreamsLookup struct { + feedParamKey string + feeds []string + timeParamKey string + time *big.Int + extraData []byte + upkeepId *big.Int + block uint64 +} + +//go:generate mockery --quiet --name HttpClient --output ./mocks/ --case=underscore +type HttpClient interface { + Do(req *http.Request) (*http.Response, error) +} + +type MercuryCredentials struct { + LegacyURL string + URL string + ClientID string + ClientKey string +} + +func (mc *MercuryCredentials) Validate() bool { + return mc.URL != "" && mc.ClientID != "" && mc.ClientKey != "" +} + +type MercuryData struct { + Index int + Error error + Retryable bool + Bytes [][]byte + State PipelineExecutionState +} + +// MercuryV02Response represents a JSON structure used by Mercury v0.2 +type MercuryV02Response struct { + ChainlinkBlob string `json:"chainlinkBlob"` +} + +// MercuryV03Response represents a JSON structure used by Mercury v0.3 +type MercuryV03Response struct { + Reports []MercuryV03Report `json:"reports"` +} + +type MercuryV03Report struct { + FeedID string `json:"feedID"` // feed id in hex encoded + ValidFromTimestamp uint32 `json:"validFromTimestamp"` + ObservationsTimestamp uint32 `json:"observationsTimestamp"` + FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier +} + +const ( + // DefaultAllowListExpiration decides how long an upkeep's allow list info will be valid for. + DefaultAllowListExpiration = 20 * time.Minute + // CleanupInterval decides when the expired items in cache will be deleted. + CleanupInterval = 25 * time.Minute +) + +const ( + ApplicationJson = "application/json" + BlockNumber = "blockNumber" // valid for v0.2 + FeedIDs = "feedIDs" // valid for v0.3 + FeedIdHex = "feedIdHex" // valid for v0.2 + HeaderAuthorization = "Authorization" + HeaderContentType = "Content-Type" + HeaderTimestamp = "X-Authorization-Timestamp" + HeaderSignature = "X-Authorization-Signature-SHA256" + HeaderUpkeepId = "X-Authorization-Upkeep-Id" + MercuryPathV2 = "/client?" // only used to access mercury v0.2 server + MercuryBatchPathV3 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server + RetryDelay = 500 * time.Millisecond + Timestamp = "timestamp" // valid for v0.3 + TotalAttempt = 3 + UserId = "userId" +) + +type UpkeepFailureReason uint8 +type PipelineExecutionState uint8 + +const ( + // upkeep failure onchain reasons + UpkeepFailureReasonNone UpkeepFailureReason = 0 + UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 + UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 + UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 + UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 + UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 + UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 + UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 + UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 + UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 + // leaving a gap here for more onchain failure reasons in the future + // upkeep failure offchain reasons + UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 + UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 + UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 + UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 + UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 + + // pipeline execution error + NoPipelineError PipelineExecutionState = 0 + CheckBlockTooOld PipelineExecutionState = 1 + CheckBlockInvalid PipelineExecutionState = 2 + RpcFlakyFailure PipelineExecutionState = 3 + MercuryFlakyFailure PipelineExecutionState = 4 + PackUnpackDecodeFailed PipelineExecutionState = 5 + MercuryUnmarshalError PipelineExecutionState = 6 + InvalidMercuryRequest PipelineExecutionState = 7 + InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized PipelineExecutionState = 9 +) + +// UpkeepPrivilegeConfig represents the administrative offchain config for each upkeep. It can be set by s_upkeepPrivilegeManager +// role on the registry. Upkeeps allowed to use Mercury server will have this set to true. +type UpkeepPrivilegeConfig struct { + MercuryEnabled bool `json:"mercuryEnabled"` +} + +// generateHMAC calculates a user HMAC for Mercury server authentication. +func (mlh *MercuryLookupHandler) generateHMAC(method string, path string, body []byte, clientId string, secret string, ts int64) string { + bodyHash := sha256.New() + bodyHash.Write(body) + hashString := fmt.Sprintf("%s %s %s %s %d", + method, + path, + hex.EncodeToString(bodyHash.Sum(nil)), + clientId, + ts) + signedMessage := hmac.New(sha256.New, []byte(secret)) + signedMessage.Write([]byte(hashString)) + userHmac := hex.EncodeToString(signedMessage.Sum(nil)) + return userHmac +} + +// singleFeedRequest sends a v0.2 Mercury request for a single feed report. +func (mlh *MercuryLookupHandler) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, ml *StreamsLookup) { + q := url.Values{ + ml.feedParamKey: {ml.feeds[index]}, + ml.timeParamKey: {ml.time.String()}, + } + mercuryURL := mlh.credentials.LegacyURL + reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, MercuryPathV2, q.Encode()) + // mlh.logger.Debugf("request URL for upkeep %s feed %s: %s", ml.upkeepId.String(), ml.feeds[index], reqUrl) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- MercuryData{Index: index, Error: err, Retryable: false, State: InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mlh.generateHMAC(http.MethodGet, MercuryPathV2+q.Encode(), []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) + req.Header.Set(HeaderContentType, ApplicationJson) + req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) + req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) + req.Header.Set(HeaderSignature, signature) + + // in the case of multiple retries here, use the last attempt's data + state := NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + retryable = false + resp, err1 := mlh.httpClient.Do(req) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup GET request failed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) + retryable = true + state = MercuryFlakyFailure + return err1 + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + // mlh.logger.Errorf("Encountered error when closing the body of the response in single feed: %s", err) + } + }(resp.Body) + + body, err1 := io.ReadAll(resp.Body) + if err1 != nil { + retryable = false + state = InvalidMercuryResponse + return err1 + } + + if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { + // mlh.logger.Errorw("StreamsLookup received retryable status code", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "statusCode", resp.StatusCode, "feed", ml.feeds[index]) + retryable = true + state = MercuryFlakyFailure + return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) + } else if resp.StatusCode != http.StatusOK { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("StreamsLookup upkeep %s block %s received status code %d for feed %s", ml.upkeepId.String(), ml.time.String(), resp.StatusCode, ml.feeds[index]) + } + + // mlh.logger.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", ml.time.String(), ml.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + + var m MercuryV02Response + err1 = json.Unmarshal(body, &m) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "feed", ml.feeds[index], "error", err1) + retryable = false + state = MercuryUnmarshalError + return err1 + } + blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to decode chainlinkBlob for feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "blob", m.ChainlinkBlob, "feed", ml.feeds[index], "error", err1) + retryable = false + state = InvalidMercuryResponse + return err1 + } + ch <- MercuryData{ + Index: index, + Bytes: [][]byte{blobBytes}, + Retryable: false, + State: NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 404 Not Found or 500 Internal Server Error + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + }), + retry.Context(ctx), + retry.Delay(RetryDelay), + retry.Attempts(TotalAttempt)) + + if !sent { + md := MercuryData{ + Index: index, + Bytes: [][]byte{}, + Retryable: retryable, + Error: fmt.Errorf("failed to request feed for %s: %w", ml.feeds[index], retryErr), + State: state, + } + ch <- md + } +} + +// multiFeedsRequest sends a Mercury v0.3 request for a multi-feed report +func (mlh *MercuryLookupHandler) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, ml *StreamsLookup) { + params := fmt.Sprintf("%s=%s&%s=%s", FeedIDs, strings.Join(ml.feeds, ","), Timestamp, ml.time.String()) + reqUrl := fmt.Sprintf("%s%s%s", mlh.credentials.URL, MercuryBatchPathV3, params) + // mlh.logger.Debugf("request URL for upkeep %s userId %s: %s", ml.upkeepId.String(), mlh.credentials.ClientID, reqUrl) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) + if err != nil { + ch <- MercuryData{Index: 0, Error: err, Retryable: false, State: InvalidMercuryRequest} + return + } + + ts := time.Now().UTC().UnixMilli() + signature := mlh.generateHMAC(http.MethodGet, MercuryBatchPathV3+params, []byte{}, mlh.credentials.ClientID, mlh.credentials.ClientKey, ts) + req.Header.Set(HeaderContentType, ApplicationJson) + // username here is often referred to as user id + req.Header.Set(HeaderAuthorization, mlh.credentials.ClientID) + req.Header.Set(HeaderTimestamp, strconv.FormatInt(ts, 10)) + req.Header.Set(HeaderSignature, signature) + // mercury will inspect authorization headers above to make sure this user (in automation's context, this node) is eligible to access mercury + // and if it has an automation role. it will then look at this upkeep id to check if it has access to all the requested feeds. + req.Header.Set(HeaderUpkeepId, ml.upkeepId.String()) + + // in the case of multiple retries here, use the last attempt's data + state := NoPipelineError + retryable := false + sent := false + retryErr := retry.Do( + func() error { + retryable = false + resp, err1 := mlh.httpClient.Do(req) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup GET request fails for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) + retryable = true + state = MercuryFlakyFailure + return err1 + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + // mlh.logger.Errorf("Encountered error when closing the body of the response in the multi feed: %s", err) + } + }(resp.Body) + body, err1 := io.ReadAll(resp.Body) + if err1 != nil { + retryable = false + state = InvalidMercuryResponse + return err1 + } + + // mlh.logger.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + if resp.StatusCode == http.StatusUnauthorized { + retryable = false + state = UpkeepNotAuthorized + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusBadRequest { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode == http.StatusInternalServerError { + retryable = true + state = MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusInternalServerError) + } else if resp.StatusCode == 420 { + // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } else if resp.StatusCode != http.StatusOK { + retryable = false + state = InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", ml.time.String(), ml.upkeepId.String(), resp.StatusCode) + } + + var response MercuryV03Response + err1 = json.Unmarshal(body, &response) + if err1 != nil { + // mlh.logger.Errorw("StreamsLookup failed to unmarshal body to MercuryResponse for multi feed", "upkeepID", ml.upkeepId.String(), "time", ml.time.String(), "error", err1) + retryable = false + state = MercuryUnmarshalError + return err1 + } + // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract + // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated + if len(response.Reports) != len(ml.feeds) { + // TODO: AUTO-5044: calculate what reports are missing and log a warning + retryable = true + state = MercuryFlakyFailure + return fmt.Errorf("%d", http.StatusNotFound) + } + var reportBytes [][]byte + for _, rsp := range response.Reports { + b, err := hexutil.Decode(rsp.FullReport) + if err != nil { + retryable = false + state = InvalidMercuryResponse + return err + } + reportBytes = append(reportBytes, b) + } + ch <- MercuryData{ + Index: 0, + Bytes: reportBytes, + Retryable: false, + State: NoPipelineError, + } + sent = true + return nil + }, + // only retry when the error is 404 Not Found or 500 Internal Server Error + retry.RetryIf(func(err error) bool { + return err.Error() == fmt.Sprintf("%d", http.StatusNotFound) || err.Error() == fmt.Sprintf("%d", http.StatusInternalServerError) + }), + retry.Context(ctx), + retry.Delay(RetryDelay), + retry.Attempts(TotalAttempt)) + + if !sent { + md := MercuryData{ + Index: 0, + Bytes: [][]byte{}, + Retryable: retryable, + Error: retryErr, + State: state, + } + ch <- md + } +} + +// doMercuryRequest sends requests to Mercury API to retrieve ChainlinkBlob. +func (mlh *MercuryLookupHandler) doMercuryRequest(ctx context.Context, ml *StreamsLookup) (PipelineExecutionState, UpkeepFailureReason, [][]byte, bool, error) { + var isMercuryV03 bool + resultLen := len(ml.feeds) + ch := make(chan MercuryData, resultLen) + if len(ml.feeds) == 0 { + return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) + } + if ml.feedParamKey == FeedIdHex && ml.timeParamKey == BlockNumber { + // only v0.2 + for i := range ml.feeds { + go mlh.singleFeedRequest(ctx, ch, i, ml) + } + } else if ml.feedParamKey == FeedIDs && ml.timeParamKey == Timestamp { + // only v0.3 + resultLen = 1 + isMercuryV03 = true + ch = make(chan MercuryData, resultLen) + go mlh.multiFeedsRequest(ctx, ch, ml) + } else { + return NoPipelineError, UpkeepFailureReasonInvalidRevertDataInput, nil, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", ml.feedParamKey, ml.timeParamKey, ml.feeds) + } + + var reqErr error + results := make([][]byte, len(ml.feeds)) + retryable := true + allSuccess := true + // in v0.2, use the last execution error as the state, if no execution errors, state will be no error + state := NoPipelineError + for i := 0; i < resultLen; i++ { + m := <-ch + if m.Error != nil { + if reqErr == nil { + reqErr = errors.New(m.Error.Error()) + } else { + reqErr = errors.New(reqErr.Error() + m.Error.Error()) + } + retryable = retryable && m.Retryable + allSuccess = false + if m.State != NoPipelineError { + state = m.State + } + continue + } + if isMercuryV03 { + results = m.Bytes + } else { + results[m.Index] = m.Bytes[0] + } + } + // only retry when not all successful AND none are not retryable + return state, UpkeepFailureReasonNone, results, retryable && !allSuccess, reqErr +} + +// decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string timeParamKey, uint256 time, byte[] extraData) +// func (mlh *MercuryLookupHandler) decodeStreamsLookup(data []byte) (*StreamsLookup, error) { +// e := mlh.mercuryConfig.Abi.Errors["StreamsLookup"] +// unpack, err := e.Unpack(data) +// if err != nil { +// return nil, fmt.Errorf("unpack error: %w", err) +// } +// errorParameters := unpack.([]interface{}) + +// return &StreamsLookup{ +// feedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), +// feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), +// timeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), +// time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), +// extraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), +// }, nil +// } + +// allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if +// this upkeep is allowed to use Mercury service. +// func (mlh *MercuryLookupHandler) allowedToUseMercury(upkeep models.Upkeep) (bool, error) { +// allowed, ok := mlh.mercuryConfig.AllowListCache.Get(upkeep.Admin.Hex()) +// if ok { +// return allowed.(bool), nil +// } + +// if upkeep.UpkeepPrivilegeConfig == nil { +// return false, fmt.Errorf("the upkeep privilege config was not retrieved for upkeep with ID %s", upkeep.UpkeepID) +// } + +// if len(upkeep.UpkeepPrivilegeConfig) == 0 { +// return false, fmt.Errorf("the upkeep privilege config is empty") +// } + +// var a UpkeepPrivilegeConfig +// err := json.Unmarshal(upkeep.UpkeepPrivilegeConfig, &a) +// if err != nil { +// return false, fmt.Errorf("failed to unmarshal privilege config for upkeep ID %s: %v", upkeep.UpkeepID, err) +// } + +// mlh.mercuryConfig.AllowListCache.Set(upkeep.Admin.Hex(), a.MercuryEnabled, cache.DefaultExpiration) +// return a.MercuryEnabled, nil +// } + +func (mlh *MercuryLookupHandler) CheckCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup, registryABI ethabi.ABI, registryAddress common.Address) (hexutil.Bytes, error) { + payload, err := registryABI.Pack("checkCallback", lookup.upkeepId, values, lookup.extraData) + if err != nil { + return nil, err + } + + var theBytes hexutil.Bytes + args := map[string]interface{}{ + "to": registryAddress.Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + err = mlh.rpcClient.CallContext(ctx, &theBytes, "eth_call", args, hexutil.EncodeUint64(lookup.block)) + if err != nil { + return nil, err + } + return theBytes, nil +} diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index ed8155d1779..d03dcec097f 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -225,6 +225,49 @@ func explorerLinkPrefix(chainID int64) (prefix string) { return } +func automationExplorerNetworkName(chainID int64) (prefix string) { + switch chainID { + case 1: // ETH mainnet + prefix = "mainnet" + case 5: // Goerli + prefix = "goerli" + case 11155111: // Sepolia + prefix = "sepolia" + + case 420: // Optimism Goerli + prefix = "optimism-goerli" + + case ArbitrumGoerliChainID: // Arbitrum Goerli + prefix = "arbitrum-goerli" + case ArbitrumOneChainID: // Arbitrum mainnet + prefix = "arbitrum" + + case 56: // BSC mainnet + prefix = "bsc" + case 97: // BSC testnet + prefix = "bnb-chain-testnet" + + case 137: // Polygon mainnet + prefix = "polygon" + case 80001: // Polygon Mumbai testnet + prefix = "mumbai" + + case 250: // Fantom mainnet + prefix = "fantom" + case 4002: // Fantom testnet + prefix = "fantom-testnet" + + case 43114: // Avalanche mainnet + prefix = "avalanche" + case 43113: // Avalanche testnet + prefix = "fuji" + + default: // Unknown chain, return prefix as-is + prefix = "" + } + return +} + // ExplorerLink creates a block explorer link for the given transaction hash. If the chain ID is // unrecognized, the hash is returned as-is. func ExplorerLink(chainID int64, txHash common.Hash) string { @@ -245,6 +288,10 @@ func ContractExplorerLink(chainID int64, contractAddress common.Address) string return contractAddress.Hex() } +func TenderlySimLink(simID string) string { + return fmt.Sprintf("https://dashboard.tenderly.co/simulator/%s", simID) +} + // ConfirmTXMined confirms that the given transaction is mined and prints useful execution information. func ConfirmTXMined(context context.Context, client *ethclient.Client, transaction *types.Transaction, chainID int64, txInfo ...string) (receipt *types.Receipt) { fmt.Println("Executing TX", ExplorerLink(chainID, transaction.Hash()), txInfo) @@ -535,3 +582,7 @@ func IsAvaxNetwork(chainID int64) bool { chainID == 335 || // DFK testnet chainID == 53935 // DFK mainnet } + +func UpkeepLink(chainID int64, upkeepID *big.Int) string { + return fmt.Sprintf("https://automation.chain.link/%s/%s", automationExplorerNetworkName(chainID), upkeepID.String()) +} diff --git a/core/scripts/common/vrf/constants/constants.go b/core/scripts/common/vrf/constants/constants.go new file mode 100644 index 00000000000..b21f6b0b323 --- /dev/null +++ b/core/scripts/common/vrf/constants/constants.go @@ -0,0 +1,34 @@ +package constants + +import ( + "math/big" +) + +var ( + SubscriptionBalanceJuels = "1e19" + SubscriptionBalanceNativeWei = "1e18" + + // optional flags + FallbackWeiPerUnitLink = big.NewInt(6e16) + BatchFulfillmentEnabled = true + MinConfs = 3 + NodeSendingKeyFundingAmount = "1e17" + MaxGasLimit = int64(2.5e6) + StalenessSeconds = int64(86400) + GasAfterPayment = int64(33285) + + //vrfv2 + FlatFeeTier1 = int64(500) + FlatFeeTier2 = int64(500) + FlatFeeTier3 = int64(500) + FlatFeeTier4 = int64(500) + FlatFeeTier5 = int64(500) + ReqsForTier2 = int64(0) + ReqsForTier3 = int64(0) + ReqsForTier4 = int64(0) + ReqsForTier5 = int64(0) + + //vrfv2plus + FlatFeeLinkPPM = int64(500) + FlatFeeNativePPM = int64(500) +) diff --git a/core/scripts/vrfv2/testnet/docker/db/create-multiple-databases.sh b/core/scripts/common/vrf/docker/db/create-multiple-databases.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/db/create-multiple-databases.sh rename to core/scripts/common/vrf/docker/db/create-multiple-databases.sh diff --git a/core/scripts/vrfv2/testnet/docker/docker-compose.yml b/core/scripts/common/vrf/docker/docker-compose.yml similarity index 98% rename from core/scripts/vrfv2/testnet/docker/docker-compose.yml rename to core/scripts/common/vrf/docker/docker-compose.yml index d31c50f3463..5c14c4670d8 100644 --- a/core/scripts/vrfv2/testnet/docker/docker-compose.yml +++ b/core/scripts/common/vrf/docker/docker-compose.yml @@ -132,9 +132,9 @@ services: secrets: node_password: - file: ./secrets/password.txt + file: secrets/password.txt apicredentials: - file: ./secrets/apicredentials + file: secrets/apicredentials volumes: docker-compose-db: diff --git a/core/scripts/vrfv2/testnet/docker/sample.env b/core/scripts/common/vrf/docker/sample.env similarity index 100% rename from core/scripts/vrfv2/testnet/docker/sample.env rename to core/scripts/common/vrf/docker/sample.env diff --git a/core/scripts/vrfv2/testnet/docker/secrets/apicredentials b/core/scripts/common/vrf/docker/secrets/apicredentials similarity index 100% rename from core/scripts/vrfv2/testnet/docker/secrets/apicredentials rename to core/scripts/common/vrf/docker/secrets/apicredentials diff --git a/core/scripts/vrfv2/testnet/docker/secrets/password.txt b/core/scripts/common/vrf/docker/secrets/password.txt similarity index 100% rename from core/scripts/vrfv2/testnet/docker/secrets/password.txt rename to core/scripts/common/vrf/docker/secrets/password.txt diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/base.toml b/core/scripts/common/vrf/docker/toml-config/base.toml similarity index 96% rename from core/scripts/vrfv2/testnet/docker/toml-config/base.toml rename to core/scripts/common/vrf/docker/toml-config/base.toml index 0bb83beb94a..39aab2e63ab 100644 --- a/core/scripts/vrfv2/testnet/docker/toml-config/base.toml +++ b/core/scripts/common/vrf/docker/toml-config/base.toml @@ -26,6 +26,5 @@ HTTPSPort = 0 [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ['0.0.0.0:6690'] ListenAddresses = ['0.0.0.0:6690'] diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/bhf.toml b/core/scripts/common/vrf/docker/toml-config/bhf.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/bhf.toml rename to core/scripts/common/vrf/docker/toml-config/bhf.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/bhs.toml b/core/scripts/common/vrf/docker/toml-config/bhs.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/bhs.toml rename to core/scripts/common/vrf/docker/toml-config/bhs.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/rpc-nodes.toml b/core/scripts/common/vrf/docker/toml-config/rpc-nodes.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/rpc-nodes.toml rename to core/scripts/common/vrf/docker/toml-config/rpc-nodes.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/secrets.toml b/core/scripts/common/vrf/docker/toml-config/secrets.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/secrets.toml rename to core/scripts/common/vrf/docker/toml-config/secrets.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml b/core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml similarity index 81% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml index a39c6b15c57..ba71abe92fc 100644 --- a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup-other-chains.toml +++ b/core/scripts/common/vrf/docker/toml-config/vrf-backup-other-chains.toml @@ -1,5 +1,5 @@ [Feature] -LogPoller = false #VRF V2 uses Log Broadcast3er instead of Log poller +LogPoller = false #VRF V2 uses Log Broadcaster instead of Log poller [[EVM]] ChainID = '11155111' diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup.toml b/core/scripts/common/vrf/docker/toml-config/vrf-backup.toml similarity index 100% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-backup.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-backup.toml diff --git a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml b/core/scripts/common/vrf/docker/toml-config/vrf-primary.toml similarity index 76% rename from core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml rename to core/scripts/common/vrf/docker/toml-config/vrf-primary.toml index 67cd33659fb..6cb78789b23 100644 --- a/core/scripts/vrfv2/testnet/docker/toml-config/vrf-primary.toml +++ b/core/scripts/common/vrf/docker/toml-config/vrf-primary.toml @@ -1,5 +1,5 @@ [Feature] -LogPoller = false #VRF V2 uses Log Broadcast3er instead of Log poller +LogPoller = false #VRF V2 uses Log Broadcaster instead of Log poller [[EVM]] ChainID = '11155111' diff --git a/core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-it.sh b/core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-it.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-it.sh rename to core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-it.sh diff --git a/core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-others.sh b/core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-others.sh similarity index 100% rename from core/scripts/vrfv2/testnet/docker/wait-for-others/docker-wait-for-others.sh rename to core/scripts/common/vrf/docker/wait-for-others/docker-wait-for-others.sh diff --git a/core/scripts/vrfv2/testnet/jobs/jobs.go b/core/scripts/common/vrf/jobs/jobs.go similarity index 55% rename from core/scripts/vrfv2/testnet/jobs/jobs.go rename to core/scripts/common/vrf/jobs/jobs.go index 8ff0195bfa8..674cca175c8 100644 --- a/core/scripts/vrfv2/testnet/jobs/jobs.go +++ b/core/scripts/common/vrf/jobs/jobs.go @@ -1,7 +1,7 @@ package jobs var ( - VRFJobFormatted = `type = "vrf" + VRFV2JobFormatted = `type = "vrf" name = "vrf_v2" schemaVersion = 1 coordinatorAddress = "%s" @@ -38,6 +38,46 @@ simulate [type=ethcall decode_log->vrf->estimate_gas->simulate """` + VRFV2PlusJobFormatted = ` +type = "vrf" +name = "vrf_v2_plus" +schemaVersion = 1 +coordinatorAddress = "%s" +batchCoordinatorAddress = "%s" +batchFulfillmentEnabled = %t +batchFulfillmentGasMultiplier = 1.1 +publicKey = "%s" +minIncomingConfirmations = %d +evmChainID = "%d" +fromAddresses = ["%s"] +pollPeriod = "300ms" +requestTimeout = "30m0s" +observationSource = """ +decode_log [type=ethabidecodelog + abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint256 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,bytes extraArgs,address indexed sender)" + data="$(jobRun.logData)" + topics="$(jobRun.logTopics)"] +generate_proof [type=vrfv2plus + publicKey="$(jobSpec.publicKey)" + requestBlockHash="$(jobRun.logBlockHash)" + requestBlockNumber="$(jobRun.logBlockNumber)" + topics="$(jobRun.logTopics)"] +estimate_gas [type=estimategaslimit + to="%s" + multiplier="1.1" + data="$(generate_proof.output)"] +simulate_fulfillment [type=ethcall + from="%s" + to="%s" + gas="$(estimate_gas)" + gasPrice="$(jobSpec.maxGasPrice)" + extractRevertReason=true + contract="%s" + data="$(generate_proof.output)"] +decode_log->generate_proof->estimate_gas->simulate_fulfillment +""" +` + BHSJobFormatted = `type = "blockhashstore" schemaVersion = 1 name = "blockhashstore" diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go new file mode 100644 index 00000000000..bd0e3bbe364 --- /dev/null +++ b/core/scripts/common/vrf/model/model.go @@ -0,0 +1,46 @@ +package model + +import ( + "github.com/ethereum/go-ethereum/common" + "math/big" +) + +var ( + VRFPrimaryNodeName = "vrf-primary-node" + VRFBackupNodeName = "vrf-backup-node" + BHSNodeName = "bhs-node" + BHSBackupNodeName = "bhs-backup-node" + BHFNodeName = "bhf-node" +) + +type Node struct { + URL string + CredsFile string + SendingKeys []SendingKey + NumberOfSendingKeysToCreate int + SendingKeyFundingAmount *big.Int + VrfKeys []string + jobSpec string +} + +type SendingKey struct { + Address string + BalanceEth *big.Int +} + +type JobSpecs struct { + VRFPrimaryNode string + VRFBackupyNode string + BHSNode string + BHSBackupNode string + BHFNode string +} + +type ContractAddresses struct { + LinkAddress string + LinkEthAddress string + BhsContractAddress common.Address + BatchBHSAddress common.Address + CoordinatorAddress common.Address + BatchCoordinatorAddress common.Address +} diff --git a/core/scripts/vrfv2/testnet/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md similarity index 72% rename from core/scripts/vrfv2/testnet/setup-envs/README.md rename to core/scripts/common/vrf/setup-envs/README.md index a36e3829c43..33515338a24 100644 --- a/core/scripts/vrfv2/testnet/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -4,8 +4,8 @@ * Currently possible to fund all nodes with one amount of native tokens ## Commands: 1. If using Docker Compose - 1. create `.env` file in `core/scripts/vrfv2/testnet/docker` (can use `sample.env` file as an example) - 2. go to `core/scripts/vrfv2/testnet/docker` folder and start containers - `docker compose up` + 1. create `.env` file in `core/scripts/common/vrf/docker` (can use `sample.env` file as an example) + 2. go to `core/scripts/common/vrf/docker` folder and start containers - `docker compose up` 2. Update [rpc-nodes.toml](..%2Fdocker%2Ftoml-config%2Frpc-nodes.toml) with relevant RPC nodes 3. Create files with credentials desirably outside `chainlink` repo (just not to push creds accidentally). Populate the files with relevant credentials for the nodes 4. Ensure that following env variables are set @@ -14,9 +14,10 @@ export ETH_URL= export ETH_CHAIN_ID= export ACCOUNT_KEY= ``` -5. execute from `core/scripts/vrfv2/testnet/setup-envs` folder +5. execute from `core/scripts/common/vrf/setup-envs` folder ``` go run . \ +--vrf-version="v2plus" \ --vrf-primary-node-url=http://localhost:6610 \ --vrf-primary-creds-file \ --vrf-backup-node-url=http://localhost:6611 \ @@ -27,13 +28,14 @@ go run . \ --bhs-bk-creds-file \ --bhf-node-url=http://localhost:6614 \ --bhf-creds-file \ ---deploy-contracts true \ ---batch-fulfillment-enabled true \ ---min-confs 1 \ ---num-eth-keys 5 \ ---num-vrf-keys 1 \ ---sending-key-funding-amount 100000000000000000 - +--deploy-contracts-and-create-jobs="true" \ +--subscription-balance="1e19" \ +--subscription-balance-native="1e18" \ +--batch-fulfillment-enabled="true" \ +--min-confs=3 \ +--num-eth-keys=1 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" ``` Optional parameters - will not be deployed if specified (NOT WORKING YET) diff --git a/core/scripts/vrfv2/testnet/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go similarity index 71% rename from core/scripts/vrfv2/testnet/setup-envs/main.go rename to core/scripts/common/vrf/setup-envs/main.go index 9e6edf725e5..6748408f476 100644 --- a/core/scripts/vrfv2/testnet/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -5,18 +5,23 @@ import ( "encoding/json" "flag" "fmt" + "io" + "math/big" + "os" + "strings" + "github.com/ethereum/go-ethereum/common" + "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/constants" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/scripts" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" clcmd "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/urfave/cli" - "io" - "math/big" - "os" - "strings" ) func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { @@ -54,7 +59,7 @@ func main() { bhsNodeURL := flag.String("bhs-node-url", "", "remote node URL") bhsBackupNodeURL := flag.String("bhs-backup-node-url", "", "remote node URL") bhfNodeURL := flag.String("bhf-node-url", "", "remote node URL") - nodeSendingKeyFundingAmount := flag.Int64("sending-key-funding-amount", constants.NodeSendingKeyFundingAmountGwei, "remote node URL") + nodeSendingKeyFundingAmount := flag.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "sending key funding amount") vrfPrimaryCredsFile := flag.String("vrf-primary-creds-file", "", "Creds to authenticate to the node") vrfBackupCredsFile := flag.String("vrf-bk-creds-file", "", "Creds to authenticate to the node") @@ -65,12 +70,15 @@ func main() { numEthKeys := flag.Int("num-eth-keys", 5, "Number of eth keys to create") maxGasPriceGwei := flag.Int("max-gas-price-gwei", -1, "Max gas price gwei of the eth keys") numVRFKeys := flag.Int("num-vrf-keys", 1, "Number of vrf keys to create") + batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether to enable batch fulfillment on Cl node") - deployContracts := flag.Bool("deploy-contracts", true, "whether to deploy contracts and create jobs") + vrfVersion := flag.String("vrf-version", "v2", "VRF version to use") + deployContractsAndCreateJobs := flag.Bool("deploy-contracts-and-create-jobs", false, "whether to deploy contracts and create jobs") - batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether to enable batch fulfillment on Cl node") - minConfs := flag.Int("min-confs", constants.MinConfs, "minimum confirmations") + subscriptionBalanceJuelsString := flag.String("subscription-balance", constants.SubscriptionBalanceJuels, "amount to fund subscription with Link token (Juels)") + subscriptionBalanceNativeWeiString := flag.String("subscription-balance-native", constants.SubscriptionBalanceNativeWei, "amount to fund subscription with native token (Wei)") + minConfs := flag.Int("min-confs", constants.MinConfs, "minimum confirmations") linkAddress := flag.String("link-address", "", "address of link token") linkEthAddress := flag.String("link-eth-feed", "", "address of link eth feed") bhsContractAddressString := flag.String("bhs-address", "", "address of BHS contract") @@ -80,41 +88,50 @@ func main() { e := helpers.SetupEnv(false) flag.Parse() - nodesMap := make(map[string]scripts.Node) + nodesMap := make(map[string]model.Node) + + if *vrfVersion != "v2" && *vrfVersion != "v2plus" { + panic(fmt.Sprintf("Invalid VRF Version `%s`. Only `v2` and `v2plus` are supported", *vrfVersion)) + } + fmt.Println("Using VRF Version:", *vrfVersion) + + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() + subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() + subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() if *vrfPrimaryNodeURL != "" { - nodesMap[scripts.VRFPrimaryNodeName] = scripts.Node{ + nodesMap[model.VRFPrimaryNodeName] = model.Node{ URL: *vrfPrimaryNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *vrfPrimaryCredsFile, } } if *vrfBackupNodeURL != "" { - nodesMap[scripts.VRFBackupNodeName] = scripts.Node{ + nodesMap[model.VRFBackupNodeName] = model.Node{ URL: *vrfBackupNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *vrfBackupCredsFile, } } if *bhsNodeURL != "" { - nodesMap[scripts.BHSNodeName] = scripts.Node{ + nodesMap[model.BHSNodeName] = model.Node{ URL: *bhsNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhsCredsFile, } } if *bhsBackupNodeURL != "" { - nodesMap[scripts.BHSBackupNodeName] = scripts.Node{ + nodesMap[model.BHSBackupNodeName] = model.Node{ URL: *bhsBackupNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhsBackupCredsFile, } } if *bhfNodeURL != "" { - nodesMap[scripts.BHFNodeName] = scripts.Node{ + nodesMap[model.BHFNodeName] = model.Node{ URL: *bhfNodeURL, - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + SendingKeyFundingAmount: fundingAmount, CredsFile: *bhfCredsFile, } } @@ -124,14 +141,14 @@ func main() { client, app := connectToNode(&node.URL, output, node.CredsFile) ethKeys := createETHKeysIfNeeded(client, app, output, numEthKeys, &node.URL, maxGasPriceGwei) - if key == scripts.VRFPrimaryNodeName { + if key == model.VRFPrimaryNodeName { vrfKeys := createVRFKeyIfNeeded(client, app, output, numVRFKeys, &node.URL) node.VrfKeys = mapVrfKeysToStringArr(vrfKeys) printVRFKeyData(vrfKeys) exportVRFKey(client, app, vrfKeys[0], output) } - if key == scripts.VRFBackupNodeName { + if key == model.VRFBackupNodeName { vrfKeys := getVRFKeys(client, app, output) node.VrfKeys = mapVrfKeysToStringArr(vrfKeys) } @@ -141,23 +158,11 @@ func main() { fundNodesIfNeeded(node, key, e) nodesMap[key] = node } - importVRFKeyToNodeIfSet(vrfBackupNodeURL, nodesMap, output, nodesMap[scripts.VRFBackupNodeName].CredsFile) - fmt.Println() + importVRFKeyToNodeIfSet(vrfBackupNodeURL, nodesMap, output, nodesMap[model.VRFBackupNodeName].CredsFile) - if *deployContracts { - feeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: uint32(constants.FlatFeeTier1), - FulfillmentFlatFeeLinkPPMTier2: uint32(constants.FlatFeeTier2), - FulfillmentFlatFeeLinkPPMTier3: uint32(constants.FlatFeeTier3), - FulfillmentFlatFeeLinkPPMTier4: uint32(constants.FlatFeeTier4), - FulfillmentFlatFeeLinkPPMTier5: uint32(constants.FlatFeeTier5), - ReqsForTier2: big.NewInt(constants.ReqsForTier2), - ReqsForTier3: big.NewInt(constants.ReqsForTier3), - ReqsForTier4: big.NewInt(constants.ReqsForTier4), - ReqsForTier5: big.NewInt(constants.ReqsForTier5), - } + if *deployContractsAndCreateJobs { - contractAddresses := scripts.ContractAddresses{ + contractAddresses := model.ContractAddresses{ LinkAddress: *linkAddress, LinkEthAddress: *linkEthAddress, BhsContractAddress: common.HexToAddress(*bhsContractAddressString), @@ -166,24 +171,65 @@ func main() { BatchCoordinatorAddress: common.HexToAddress(*batchCoordinatorAddressString), } - coordinatorConfig := scripts.CoordinatorConfig{ - MinConfs: minConfs, - MaxGasLimit: &constants.MaxGasLimit, - StalenessSeconds: &constants.StalenessSeconds, - GasAfterPayment: &constants.GasAfterPayment, - FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, - FeeConfig: feeConfig, - } + var jobSpecs model.JobSpecs + + switch *vrfVersion { + case "v2": + feeConfigV2 := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: uint32(constants.FlatFeeTier1), + FulfillmentFlatFeeLinkPPMTier2: uint32(constants.FlatFeeTier2), + FulfillmentFlatFeeLinkPPMTier3: uint32(constants.FlatFeeTier3), + FulfillmentFlatFeeLinkPPMTier4: uint32(constants.FlatFeeTier4), + FulfillmentFlatFeeLinkPPMTier5: uint32(constants.FlatFeeTier5), + ReqsForTier2: big.NewInt(constants.ReqsForTier2), + ReqsForTier3: big.NewInt(constants.ReqsForTier3), + ReqsForTier4: big.NewInt(constants.ReqsForTier4), + ReqsForTier5: big.NewInt(constants.ReqsForTier5), + } + + coordinatorConfigV2 := v2scripts.CoordinatorConfigV2{ + MinConfs: minConfs, + MaxGasLimit: &constants.MaxGasLimit, + StalenessSeconds: &constants.StalenessSeconds, + GasAfterPayment: &constants.GasAfterPayment, + FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, + FeeConfig: feeConfigV2, + } - jobSpecs := scripts.VRFV2DeployUniverse( - e, - constants.SubscriptionBalanceJuels, - &nodesMap[scripts.VRFPrimaryNodeName].VrfKeys[0], - contractAddresses, - coordinatorConfig, - *batchFulfillmentEnabled, - nodesMap, - ) + jobSpecs = v2scripts.VRFV2DeployUniverse( + e, + subscriptionBalanceJuels, + &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + contractAddresses, + coordinatorConfigV2, + *batchFulfillmentEnabled, + nodesMap, + ) + case "v2plus": + feeConfigV2Plus := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: uint32(constants.FlatFeeLinkPPM), + FulfillmentFlatFeeNativePPM: uint32(constants.FlatFeeNativePPM), + } + coordinatorConfigV2Plus := v2plusscripts.CoordinatorConfigV2Plus{ + MinConfs: minConfs, + MaxGasLimit: &constants.MaxGasLimit, + StalenessSeconds: &constants.StalenessSeconds, + GasAfterPayment: &constants.GasAfterPayment, + FallbackWeiPerUnitLink: constants.FallbackWeiPerUnitLink, + FeeConfig: feeConfigV2Plus, + } + + jobSpecs = v2plusscripts.VRFV2PlusDeployUniverse( + e, + subscriptionBalanceJuels, + subscriptionBalanceNativeWei, + &nodesMap[model.VRFPrimaryNodeName].VrfKeys[0], + contractAddresses, + coordinatorConfigV2Plus, + *batchFulfillmentEnabled, + nodesMap, + ) + } for key, node := range nodesMap { client, app := connectToNode(&node.URL, output, node.CredsFile) @@ -196,41 +242,43 @@ func main() { deleteJob(jobID, client, app, output) } //CREATE JOBS + switch key { - case scripts.VRFPrimaryNodeName: + case model.VRFPrimaryNodeName: createJob(jobSpecs.VRFPrimaryNode, client, app, output) - case scripts.VRFBackupNodeName: + case model.VRFBackupNodeName: createJob(jobSpecs.VRFBackupyNode, client, app, output) - case scripts.BHSNodeName: + case model.BHSNodeName: createJob(jobSpecs.BHSNode, client, app, output) - case scripts.BHSBackupNodeName: + case model.BHSBackupNodeName: createJob(jobSpecs.BHSBackupNode, client, app, output) - case scripts.BHFNodeName: + case model.BHFNodeName: createJob(jobSpecs.BHFNode, client, app, output) } } } - } -func fundNodesIfNeeded(node scripts.Node, key string, e helpers.Environment) { - if node.SendingKeyFundingAmount.Int64() > 0 { - fmt.Println("\nFunding", key, "Node's Sending Keys...") +func fundNodesIfNeeded(node model.Node, key string, e helpers.Environment) { + if node.SendingKeyFundingAmount.Cmp(big.NewInt(0)) == 1 { + fmt.Println("\nFunding", key, "Node's Sending Keys. Need to fund each key with", node.SendingKeyFundingAmount, "wei") for _, sendingKey := range node.SendingKeys { - fundingToSendWei := node.SendingKeyFundingAmount.Int64() - sendingKey.BalanceEth.Int64() - if fundingToSendWei > 0 { - helpers.FundNode(e, sendingKey.Address, big.NewInt(fundingToSendWei)) + fundingToSendWei := new(big.Int).Sub(node.SendingKeyFundingAmount, sendingKey.BalanceEth) + if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { + helpers.FundNode(e, sendingKey.Address, fundingToSendWei) } else { - fmt.Println("\nSkipping Funding", sendingKey.Address, "since it has", sendingKey.BalanceEth.Int64(), "wei") + fmt.Println("\nSkipping Funding", sendingKey.Address, "since it has", sendingKey.BalanceEth.String(), "wei") } } + } else { + fmt.Println("\nSkipping Funding", key, "Node's Sending Keys since funding amount is 0 wei") } } -func importVRFKeyToNodeIfSet(vrfBackupNodeURL *string, nodes map[string]scripts.Node, output *bytes.Buffer, file string) { +func importVRFKeyToNodeIfSet(vrfBackupNodeURL *string, nodes map[string]model.Node, output *bytes.Buffer, file string) { if *vrfBackupNodeURL != "" { - vrfBackupNode := nodes[scripts.VRFBackupNodeName] - vrfPrimaryNode := nodes[scripts.VRFBackupNodeName] + vrfBackupNode := nodes[model.VRFBackupNodeName] + vrfPrimaryNode := nodes[model.VRFBackupNodeName] if len(vrfBackupNode.VrfKeys) == 0 || vrfPrimaryNode.VrfKeys[0] != vrfBackupNode.VrfKeys[0] { client, app := connectToNode(&vrfBackupNode.URL, output, file) @@ -330,15 +378,14 @@ func printETHKeyData(ethKeys []presenters.ETHKeyResource) { fmt.Println("Address: ", ethKey.Address) fmt.Println("MaxGasPriceWei: ", ethKey.MaxGasPriceWei) fmt.Println("EthBalance: ", ethKey.EthBalance) - fmt.Println("NextNonce: ", ethKey.NextNonce) fmt.Println("-----------------------------") } } -func mapEthKeysToSendingKeyArr(ethKeys []presenters.ETHKeyResource) []scripts.SendingKey { - var sendingKeys []scripts.SendingKey +func mapEthKeysToSendingKeyArr(ethKeys []presenters.ETHKeyResource) []model.SendingKey { + var sendingKeys []model.SendingKey for _, ethKey := range ethKeys { - sendingKey := scripts.SendingKey{Address: ethKey.Address, BalanceEth: *ethKey.EthBalance.ToInt()} + sendingKey := model.SendingKey{Address: ethKey.Address, BalanceEth: ethKey.EthBalance.ToInt()} sendingKeys = append(sendingKeys, sendingKey) } return sendingKeys diff --git a/core/scripts/common/vrf/util/util.go b/core/scripts/common/vrf/util/util.go new file mode 100644 index 00000000000..751aa013201 --- /dev/null +++ b/core/scripts/common/vrf/util/util.go @@ -0,0 +1,22 @@ +package util + +import ( + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" +) + +func MapToSendingKeyArr(nodeSendingKeys []string) []model.SendingKey { + var sendingKeys []model.SendingKey + + for _, key := range nodeSendingKeys { + sendingKeys = append(sendingKeys, model.SendingKey{Address: key}) + } + return sendingKeys +} + +func MapToAddressArr(sendingKeys []model.SendingKey) []string { + var sendingKeysString []string + for _, sendingKey := range sendingKeys { + sendingKeysString = append(sendingKeysString, sendingKey.Address) + } + return sendingKeysString +} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index bb4b33eb521..c8b616a4b6e 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -7,7 +7,8 @@ replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( github.com/ava-labs/coreth v0.12.1 - github.com/docker/docker v24.0.4+incompatible + github.com/avast/retry-go v3.0.0+incompatible + github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/ethereum/go-ethereum v1.12.0 github.com/google/go-cmp v0.5.9 @@ -17,9 +18,10 @@ require ( github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb @@ -55,7 +57,6 @@ require ( github.com/ava-labs/avalanchego v1.10.1 // indirect github.com/avast/retry-go/v4 v4.5.0 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect - github.com/benbjohnson/clock v1.3.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -64,6 +65,7 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect @@ -149,14 +151,15 @@ require ( 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/grafana/pyroscope-go v1.0.2 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go v1.0.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/graph-gophers/dataloader v5.0.0+incompatible // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.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 @@ -164,7 +167,7 @@ require ( github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.4.10 // indirect + github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect @@ -196,7 +199,7 @@ require ( github.com/jmoiron/sqlx v1.3.5 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -273,19 +276,18 @@ require ( github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // 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/pressly/goose/v3 v3.15.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect + github.com/pressly/goose/v3 v3.15.1 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/prometheus v0.46.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect @@ -296,13 +298,13 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect @@ -340,31 +342,33 @@ require ( go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/atomic v1.11.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/sdk v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect - go.uber.org/zap v1.24.0 // indirect + go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.11.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/tools v0.14.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.56.2 // indirect + google.golang.org/grpc v1.58.3 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect @@ -386,7 +390,7 @@ replace ( github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 - github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 + github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 571b9b0e8ef..c4d0575bb20 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -142,6 +142,8 @@ github.com/ava-labs/avalanchego v1.10.1 h1:lBeamJ1iNq+p2oKg2nAs+A65m8vhSDjkiTDbw github.com/ava-labs/avalanchego v1.10.1/go.mod h1:ZvSXWlbkUKlbk3BsWx29a+8eVHe/WBsOxh55BSGoeRk= github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7sA= github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= +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.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -152,8 +154,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/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= @@ -242,8 +242,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= 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/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= 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= @@ -333,8 +333,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 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.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= -github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= +github.com/docker/docker v24.0.6+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= @@ -623,10 +623,10 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad 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/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= 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= @@ -634,14 +634,16 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt 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.0-rc.0 h1:mdLirNAJBxnGgyB6pjZLcs6ue/6eZGBui6gXspfq4ks= -github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0/go.mod h1:kdXbOySqcQeTxiqglW7aahTmWZy3Pgi6SYL36yvKeyA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tggROQKKcnh4eItay6z/HbHLqghBxS8g7pyMhmDio= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0/go.mod h1:hKAkSgNkL0FII46ZkJcpVEAai4KV+swlIWCKfekd1pA= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= 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.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= 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= @@ -653,6 +655,8 @@ github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfm 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/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= 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= @@ -881,8 +885,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 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.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1320,10 +1324,10 @@ 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/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.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= +github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 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= @@ -1358,20 +1362,20 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 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.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= 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.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +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-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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +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.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= @@ -1382,8 +1386,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R 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.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1436,8 +1440,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg 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/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -1454,18 +1458,18 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 h1:Db333w+fSm2e18LMikcIQHIZqgxZruW9uCUGJLUC9mI= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= @@ -1656,16 +1660,22 @@ 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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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= @@ -1693,8 +1703,9 @@ 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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1734,8 +1745,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y 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.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -1774,8 +1785,8 @@ 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1835,8 +1846,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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= @@ -1861,8 +1872,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -1955,15 +1966,17 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.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 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= 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 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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= @@ -1974,8 +1987,8 @@ 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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -2050,8 +2063,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= @@ -2170,8 +2183,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -2250,20 +2263,20 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= -modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ= -modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo= +modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= -modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= +modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= diff --git a/core/scripts/ocr2vrf/util.go b/core/scripts/ocr2vrf/util.go index f8d104a5f3e..a2ff55524d3 100644 --- a/core/scripts/ocr2vrf/util.go +++ b/core/scripts/ocr2vrf/util.go @@ -14,16 +14,17 @@ import ( "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + "github.com/urfave/cli" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/group/edwards25519" + "go.dedis.ch/kyber/v3/pairing" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2vrf/altbn_128" "github.com/smartcontractkit/ocr2vrf/dkg" "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/urfave/cli" - "go.dedis.ch/kyber/v3" - "go.dedis.ch/kyber/v3/group/edwards25519" - "go.dedis.ch/kyber/v3/pairing" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" @@ -43,11 +44,7 @@ var ( g1 = suite.G1() g2 = suite.G2() tomlConfigTemplate = ` - [P2P.V1] - Enabled = false - [P2P.V2] - Enabled = true ListenAddresses = ["127.0.0.1:8000"] [Feature] diff --git a/core/scripts/vrfv2/testnet/constants/constants.go b/core/scripts/vrfv2/testnet/constants/constants.go deleted file mode 100644 index 73356d48ffc..00000000000 --- a/core/scripts/vrfv2/testnet/constants/constants.go +++ /dev/null @@ -1,28 +0,0 @@ -package constants - -import ( - "github.com/smartcontractkit/chainlink/v2/core/assets" - "math/big" -) - -var ( - SubscriptionBalanceJuels = assets.Ether(10).ToInt() - - // optional flags - FallbackWeiPerUnitLink = big.NewInt(6e16) - BatchFulfillmentEnabled = true - MinConfs = 3 - NodeSendingKeyFundingAmountGwei = assets.GWei(0).Int64() //100000000 = 0.1 ETH - MaxGasLimit = int64(2.5e6) - StalenessSeconds = int64(86400) - GasAfterPayment = int64(33285) - FlatFeeTier1 = int64(500) - FlatFeeTier2 = int64(500) - FlatFeeTier3 = int64(500) - FlatFeeTier4 = int64(500) - FlatFeeTier5 = int64(500) - ReqsForTier2 = int64(0) - ReqsForTier3 = int64(0) - ReqsForTier4 = int64(0) - ReqsForTier5 = int64(0) -) diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index d30c0e7fca3..5b216776bd9 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -11,7 +11,7 @@ import ( "os" "strings" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/scripts" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner_test_consumer" "github.com/ethereum/go-ethereum" @@ -350,7 +350,7 @@ func main() { cmd := flag.NewFlagSet("batch-bhs-deploy", flag.ExitOnError) bhsAddr := cmd.String("bhs-address", "", "address of the blockhash store contract") helpers.ParseArgs(cmd, os.Args[2:], "bhs-address") - scripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) + v2scripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) case "batch-bhs-store": cmd := flag.NewFlagSet("batch-bhs-store", flag.ExitOnError) batchAddr := cmd.String("batch-bhs-address", "", "address of the batch bhs contract") @@ -418,12 +418,19 @@ func main() { } if *startBlock == -1 { - tx, err2 := bhs.StoreEarliest(e.Owner) - helpers.PanicErr(err2) - receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "Store Earliest") - // storeEarliest will store receipt block number minus 256 which is the earliest block - // the blockhash() instruction will work on. - *startBlock = receipt.BlockNumber.Int64() - 256 + closestBlock, err2 := v2scripts.ClosestBlock(e, common.HexToAddress(*batchAddr), uint64(*endBlock), uint64(*batchSize)) + // found a block with blockhash stored that's more recent that end block + if err2 == nil { + *startBlock = int64(closestBlock) + } else { + fmt.Println("encountered error while looking for closest block:", err2) + tx, err2 := bhs.StoreEarliest(e.Owner) + helpers.PanicErr(err2) + receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "Store Earliest") + // storeEarliest will store receipt block number minus 256 which is the earliest block + // the blockhash() instruction will work on. + *startBlock = receipt.BlockNumber.Int64() - 256 + } } // Check if the provided start block is in the BHS. If it's not, print out an appropriate @@ -476,6 +483,7 @@ func main() { helpers.PanicErr(err) fmt.Println("received receipt, continuing") + fmt.Println("there are", len(blockRange)-j, "blocks left to store") } fmt.Println("done") case "latest-head": @@ -483,14 +491,14 @@ func main() { helpers.PanicErr(err) fmt.Println("latest head number:", h.Number.String()) case "bhs-deploy": - scripts.DeployBHS(e) + v2scripts.DeployBHS(e) case "coordinator-deploy": coordinatorDeployCmd := flag.NewFlagSet("coordinator-deploy", flag.ExitOnError) coordinatorDeployLinkAddress := coordinatorDeployCmd.String("link-address", "", "address of link token") coordinatorDeployBHSAddress := coordinatorDeployCmd.String("bhs-address", "", "address of bhs") coordinatorDeployLinkEthFeedAddress := coordinatorDeployCmd.String("link-eth-feed", "", "address of link-eth-feed") helpers.ParseArgs(coordinatorDeployCmd, os.Args[2:], "link-address", "bhs-address", "link-eth-feed") - scripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) + v2scripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) case "coordinator-get-config": cmd := flag.NewFlagSet("coordinator-get-config", flag.ExitOnError) coordinatorAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -499,7 +507,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.PrintCoordinatorConfig(coordinator) + v2scripts.PrintCoordinatorConfig(coordinator) case "coordinator-set-config": cmd := flag.NewFlagSet("coordinator-set-config", flag.ExitOnError) setConfigAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -522,7 +530,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*setConfigAddress), e.Ec) helpers.PanicErr(err) - scripts.SetCoordinatorConfig( + v2scripts.SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -556,7 +564,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - scripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2scripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") @@ -684,14 +692,14 @@ func main() { helpers.PanicErr(err) fmt.Printf("Request config %+v Rw %+v Rid %+v\n", rc, rw, rid) case "deploy-universe": - scripts.DeployUniverseViaCLI(e) + v2scripts.DeployUniverseViaCLI(e) case "eoa-consumer-deploy": consumerDeployCmd := flag.NewFlagSet("eoa-consumer-deploy", flag.ExitOnError) consumerCoordinator := consumerDeployCmd.String("coordinator-address", "", "coordinator address") consumerLinkAddress := consumerDeployCmd.String("link-address", "", "link-address") helpers.ParseArgs(consumerDeployCmd, os.Args[2:], "coordinator-address", "link-address") - scripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) + v2scripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) case "eoa-load-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -708,7 +716,7 @@ func main() { loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-with-metrics-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address") - scripts.EoaLoadTestConsumerWithMetricsDeploy(e, *consumerCoordinator) + v2scripts.EoaLoadTestConsumerWithMetricsDeploy(e, *consumerCoordinator) case "eoa-vrf-owner-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-vrf-owner-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -726,7 +734,7 @@ func main() { helpers.ParseArgs(createSubCmd, os.Args[2:], "coordinator-address") coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.EoaCreateSub(e, *coordinator) + v2scripts.EoaCreateSub(e, *coordinator) case "eoa-add-sub-consumer": addSubConsCmd := flag.NewFlagSet("eoa-add-sub-consumer", flag.ExitOnError) coordinatorAddress := addSubConsCmd.String("coordinator-address", "", "coordinator address") @@ -735,7 +743,7 @@ func main() { helpers.ParseArgs(addSubConsCmd, os.Args[2:], "coordinator-address", "sub-id", "consumer-address") coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*subID), *consumerAddress) + v2scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*subID), *consumerAddress) case "eoa-create-fund-authorize-sub": // Lets just treat the owner key as the EOA controlling the sub cfaSubCmd := flag.NewFlagSet("eoa-create-fund-authorize-sub", flag.ExitOnError) @@ -1021,7 +1029,7 @@ func main() { coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - scripts.EoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, uint64(*subID)) + v2scripts.EoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, uint64(*subID)) case "eoa-read": cmd := flag.NewFlagSet("eoa-read", flag.ExitOnError) consumerAddress := cmd.String("consumer", "", "consumer address") @@ -1189,7 +1197,7 @@ func main() { linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address") - scripts.WrapperDeploy(e, + v2scripts.WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) @@ -1227,7 +1235,7 @@ func main() { maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash") - scripts.WrapperConfigure(e, + v2scripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, *coordinatorGasOverhead, @@ -1259,7 +1267,7 @@ func main() { wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "wrapper-address") - scripts.WrapperConsumerDeploy(e, + v2scripts.WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*wrapperAddress)) case "wrapper-consumer-request": @@ -1330,8 +1338,16 @@ func main() { blockNumber := cmd.Int("block-number", -1, "block number") helpers.ParseArgs(cmd, os.Args[2:]) _ = helpers.CalculateLatestBlockHeader(e, *blockNumber) + case "closest-block": + cmd := flag.NewFlagSet("closest-block", flag.ExitOnError) + blockNumber := cmd.Uint64("block-number", 0, "block number") + batchBHSAddress := cmd.String("batch-bhs-address", "", "address of the batch blockhash store") + batchSize := cmd.Uint64("batch-size", 100, "batch size") + helpers.ParseArgs(cmd, os.Args[2:], "block-number", "batch-bhs-address") + _, err := v2scripts.ClosestBlock(e, common.HexToAddress(*batchBHSAddress), *blockNumber, *batchSize) + helpers.PanicErr(err) case "wrapper-universe-deploy": - scripts.DeployWrapperUniverse(e) + v2scripts.DeployWrapperUniverse(e) default: panic("unrecognized subcommand: " + os.Args[1]) } diff --git a/core/scripts/vrfv2/testnet/scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go similarity index 83% rename from core/scripts/vrfv2/testnet/scripts/super_scripts.go rename to core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 3594636a604..f5e37005690 100644 --- a/core/scripts/vrfv2/testnet/scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -1,12 +1,14 @@ -package scripts +package v2scripts import ( "context" "encoding/hex" "flag" "fmt" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/constants" - "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" "math/big" "os" "strings" @@ -22,47 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" ) -var ( - VRFPrimaryNodeName = "vrf-primary-node" - VRFBackupNodeName = "vrf-backup-node" - BHSNodeName = "bhs-node" - BHSBackupNodeName = "bhs-backup-node" - BHFNodeName = "bhf-node" -) - -type Node struct { - URL string - CredsFile string - SendingKeys []SendingKey - NumberOfSendingKeysToCreate int - SendingKeyFundingAmount big.Int - VrfKeys []string - jobSpec string -} - -type SendingKey struct { - Address string - BalanceEth big.Int -} - -type JobSpecs struct { - VRFPrimaryNode string - VRFBackupyNode string - BHSNode string - BHSBackupNode string - BHFNode string -} - -type ContractAddresses struct { - LinkAddress string - LinkEthAddress string - BhsContractAddress common.Address - BatchBHSAddress common.Address - CoordinatorAddress common.Address - BatchCoordinatorAddress common.Address -} - -type CoordinatorConfig struct { +type CoordinatorConfigV2 struct { MinConfs *int MaxGasLimit *int64 StalenessSeconds *int64 @@ -82,8 +44,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") - subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", constants.SubscriptionBalanceJuels.String(), "amount to fund subscription") - nodeSendingKeyFundingAmount := deployCmd.Int64("sending-key-funding-amount", constants.NodeSendingKeyFundingAmountGwei, "CL node sending key funding amount") + subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", constants.SubscriptionBalanceJuels, "amount to fund subscription") + nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") @@ -127,11 +89,15 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") - nodesMap := make(map[string]Node) + nodesMap := make(map[string]model.Node) - nodesMap[VRFPrimaryNodeName] = Node{ - SendingKeys: mapToSendingKeyArr(vrfPrimaryNodeSendingKeys), - SendingKeyFundingAmount: *big.NewInt(*nodeSendingKeyFundingAmount), + fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) + if !ok { + panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) + } + nodesMap[model.VRFPrimaryNodeName] = model.Node{ + SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), + SendingKeyFundingAmount: fundingAmount, } bhsContractAddress := common.HexToAddress(bhsContractAddressString) @@ -139,7 +105,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { coordinatorAddress := common.HexToAddress(coordinatorAddressString) batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) - contractAddresses := ContractAddresses{ + contractAddresses := model.ContractAddresses{ LinkAddress: linkAddress, LinkEthAddress: linkEthAddress, BhsContractAddress: bhsContractAddress, @@ -148,7 +114,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { BatchCoordinatorAddress: batchCoordinatorAddress, } - coordinatorConfig := CoordinatorConfig{ + coordinatorConfig := CoordinatorConfigV2{ MinConfs: minConfs, MaxGasLimit: maxGasLimit, StalenessSeconds: stalenessSeconds, @@ -167,31 +133,22 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap, ) - vrfPrimaryNode := nodesMap[VRFPrimaryNodeName] + vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] fmt.Println("Funding node's sending keys...") for _, sendingKey := range vrfPrimaryNode.SendingKeys { - helpers.FundNode(e, sendingKey.Address, &vrfPrimaryNode.SendingKeyFundingAmount) + helpers.FundNode(e, sendingKey.Address, vrfPrimaryNode.SendingKeyFundingAmount) } } -func mapToSendingKeyArr(nodeSendingKeys []string) []SendingKey { - var sendingKeys []SendingKey - - for _, key := range nodeSendingKeys { - sendingKeys = append(sendingKeys, SendingKey{Address: key}) - } - return sendingKeys -} - func VRFV2DeployUniverse( e helpers.Environment, subscriptionBalanceJuels *big.Int, registerKeyUncompressedPubKey *string, - contractAddresses ContractAddresses, - coordinatorConfig CoordinatorConfig, + contractAddresses model.ContractAddresses, + coordinatorConfig CoordinatorConfigV2, batchFulfillmentEnabled bool, - nodesMap map[string]Node, -) JobSpecs { + nodesMap map[string]model.Node, +) model.JobSpecs { // Put key in ECDSA format if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { @@ -246,7 +203,7 @@ func VRFV2DeployUniverse( if contractAddresses.BatchCoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { fmt.Println("\nDeploying Batch Coordinator...") - contractAddresses.BatchCoordinatorAddress = deployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) + contractAddresses.BatchCoordinatorAddress = DeployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) } fmt.Println("\nSetting Coordinator Config...") @@ -302,31 +259,31 @@ func VRFV2DeployUniverse( fmt.Printf("Subscription %+v\n", s) formattedVrfPrimaryJobSpec := fmt.Sprintf( - jobs.VRFJobFormatted, + jobs.VRFV2JobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey *coordinatorConfig.MinConfs, //minIncomingConfirmations e.ChainID, //evmChainID - strings.Join(mapToAddressArr(nodesMap[VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[VRFPrimaryNodeName].SendingKeys[0].Address, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) formattedVrfBackupJobSpec := fmt.Sprintf( - jobs.VRFJobFormatted, + jobs.VRFV2JobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress batchFulfillmentEnabled, //batchFulfillmentEnabled compressedPkHex, //publicKey 100, //minIncomingConfirmations e.ChainID, //evmChainID - strings.Join(mapToAddressArr(nodesMap[VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses contractAddresses.CoordinatorAddress, - nodesMap[VRFPrimaryNodeName].SendingKeys[0], + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) @@ -338,7 +295,7 @@ func VRFV2DeployUniverse( 200, //lookbackBlocks contractAddresses.BhsContractAddress, //bhs address e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHSNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), //sending addresses ) formattedBHSBackupJobSpec := fmt.Sprintf( @@ -348,7 +305,7 @@ func VRFV2DeployUniverse( 200, //lookbackBlocks contractAddresses.BhsContractAddress, //bhs adreess e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses ) formattedBHFJobSpec := fmt.Sprintf( @@ -357,7 +314,7 @@ func VRFV2DeployUniverse( contractAddresses.BhsContractAddress, //bhs adreess contractAddresses.BatchBHSAddress, //batchBHS e.ChainID, //chain id - strings.Join(mapToAddressArr(nodesMap[BHFNodeName].SendingKeys), "\",\""), //sending addresses + strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), //sending addresses ) fmt.Println( @@ -379,7 +336,7 @@ func VRFV2DeployUniverse( formattedVrfPrimaryJobSpec, ) - return JobSpecs{ + return model.JobSpecs{ VRFPrimaryNode: formattedVrfPrimaryJobSpec, VRFBackupyNode: formattedVrfBackupJobSpec, BHSNode: formattedBHSJobSpec, @@ -388,14 +345,6 @@ func VRFV2DeployUniverse( } } -func mapToAddressArr(sendingKeys []SendingKey) []string { - var sendingKeysString []string - for _, sendingKey := range sendingKeys { - sendingKeysString = append(sendingKeysString, sendingKey.Address) - } - return sendingKeysString -} - func DeployWrapperUniverse(e helpers.Environment) { cmd := flag.NewFlagSet("wrapper-universe-deploy", flag.ExitOnError) linkAddress := cmd.String("link-address", "", "address of link token") diff --git a/core/scripts/vrfv2/testnet/scripts/util.go b/core/scripts/vrfv2/testnet/v2scripts/util.go similarity index 84% rename from core/scripts/vrfv2/testnet/scripts/util.go rename to core/scripts/vrfv2/testnet/v2scripts/util.go index 3b429837c93..0e348e9c01c 100644 --- a/core/scripts/vrfv2/testnet/scripts/util.go +++ b/core/scripts/vrfv2/testnet/v2scripts/util.go @@ -1,13 +1,16 @@ -package scripts +package v2scripts import ( "context" "encoding/hex" + "errors" "fmt" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" "math/big" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" @@ -50,7 +53,7 @@ func DeployCoordinator( return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { +func DeployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { _, tx, _, err := batch_vrf_coordinator_v2.DeployBatchVRFCoordinatorV2(e.Owner, e.Ec, coordinatorAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) @@ -212,3 +215,39 @@ func EoaLoadTestConsumerWithMetricsDeploy(e helpers.Environment, consumerCoordin helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } + +func ClosestBlock(e helpers.Environment, batchBHSAddress common.Address, blockMissingBlockhash uint64, batchSize uint64) (uint64, error) { + batchBHS, err := batch_blockhash_store.NewBatchBlockhashStore(batchBHSAddress, e.Ec) + if err != nil { + return 0, err + } + startBlock := blockMissingBlockhash + 1 + endBlock := startBlock + batchSize + for { + latestBlock, err := e.Ec.HeaderByNumber(context.Background(), nil) + if err != nil { + return 0, err + } + if latestBlock.Number.Uint64() < endBlock { + return 0, errors.New("closest block with blockhash not found") + } + var blockRange []*big.Int + for i := startBlock; i <= endBlock; i++ { + blockRange = append(blockRange, big.NewInt(int64(i))) + } + fmt.Println("Searching range", startBlock, "-", endBlock, "inclusive") + hashes, err := batchBHS.GetBlockhashes(nil, blockRange) + if err != nil { + return 0, err + } + for i, hash := range hashes { + if hash != (common.Hash{}) { + fmt.Println("found closest block:", startBlock+uint64(i), "hash:", hexutil.Encode(hash[:])) + fmt.Println("distance from missing block:", startBlock+uint64(i)-blockMissingBlockhash) + return startBlock + uint64(i), nil + } + } + startBlock = endBlock + 1 + endBlock = startBlock + batchSize + } +} diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 7bc64108669..0d1bf9a9481 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -6,11 +6,13 @@ import ( "encoding/hex" "flag" "fmt" + "github.com/smartcontractkit/chainlink/core/scripts/vrfv2plus/testnet/v2plusscripts" "log" "math/big" "os" "strings" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_specific_util_helper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" @@ -18,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/shopspring/decimal" @@ -48,17 +51,60 @@ import ( var ( batchCoordinatorV2PlusABI = evmtypes.MustGetABI(batch_vrf_coordinator_v2plus.BatchVRFCoordinatorV2PlusABI) - coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) ) func main() { e := helpers.SetupEnv(false) switch os.Args[1] { + case "csu-deploy": + addr, tx, _, err := chain_specific_util_helper.DeployChainSpecificUtilHelper(e.Owner, e.Ec) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "deploying chain specific util helper") + fmt.Println("deployed chain specific util helper at:", addr) + case "csu-block-number": + cmd := flag.NewFlagSet("csu-block-number", flag.ExitOnError) + csuAddress := cmd.String("csu-address", "", "address of the chain specific util helper contract") + helpers.ParseArgs(cmd, os.Args[2:], "csu-address") + csu, err := chain_specific_util_helper.NewChainSpecificUtilHelper(common.HexToAddress(*csuAddress), e.Ec) + helpers.PanicErr(err) + blockNumber, err := csu.GetBlockNumber(nil) + helpers.PanicErr(err) + fmt.Println("block number:", blockNumber) + case "csu-block-hash": + cmd := flag.NewFlagSet("csu-block-hash", flag.ExitOnError) + csuAddress := cmd.String("csu-address", "", "address of the chain specific util helper contract") + blockNumber := cmd.Uint64("block-number", 0, "block number to get the hash of") + helpers.ParseArgs(cmd, os.Args[2:], "csu-address") + csu, err := chain_specific_util_helper.NewChainSpecificUtilHelper(common.HexToAddress(*csuAddress), e.Ec) + helpers.PanicErr(err) + blockHash, err := csu.GetBlockhash(nil, *blockNumber) + helpers.PanicErr(err) + fmt.Println("block hash:", hexutil.Encode(blockHash[:])) + case "csu-current-tx-l1-gas-fees": + cmd := flag.NewFlagSet("csu-current-tx-l1-gas-fees", flag.ExitOnError) + csuAddress := cmd.String("csu-address", "", "address of the chain specific util helper contract") + calldata := cmd.String("calldata", "", "calldata to estimate gas fees for") + helpers.ParseArgs(cmd, os.Args[2:], "csu-address", "calldata") + csu, err := chain_specific_util_helper.NewChainSpecificUtilHelper(common.HexToAddress(*csuAddress), e.Ec) + helpers.PanicErr(err) + gasFees, err := csu.GetCurrentTxL1GasFees(nil, *calldata) + helpers.PanicErr(err) + fmt.Println("gas fees:", gasFees) + case "csu-l1-calldata-gas-cost": + cmd := flag.NewFlagSet("csu-l1-calldata-gas-cost", flag.ExitOnError) + csuAddress := cmd.String("csu-address", "", "address of the chain specific util helper contract") + calldataSize := cmd.String("calldata-size", "", "size of the calldata to estimate gas fees for") + helpers.ParseArgs(cmd, os.Args[2:], "csu-address", "calldata-size") + csu, err := chain_specific_util_helper.NewChainSpecificUtilHelper(common.HexToAddress(*csuAddress), e.Ec) + helpers.PanicErr(err) + gasCost, err := csu.GetL1CalldataGasCost(nil, decimal.RequireFromString(*calldataSize).BigInt()) + helpers.PanicErr(err) + fmt.Println("gas cost:", gasCost) case "smoke": - smokeTestVRF(e) + v2plusscripts.SmokeTestVRF(e) case "smoke-bhs": - smokeTestBHS(e) + v2plusscripts.SmokeTestBHS(e) case "manual-fulfill": cmd := flag.NewFlagSet("manual-fulfill", flag.ExitOnError) // In order to get the tx data for a fulfillment transaction, you can grep the @@ -291,7 +337,7 @@ func main() { cmd := flag.NewFlagSet("batch-bhs-deploy", flag.ExitOnError) bhsAddr := cmd.String("bhs-address", "", "address of the blockhash store contract") helpers.ParseArgs(cmd, os.Args[2:], "bhs-address") - deployBatchBHS(e, common.HexToAddress(*bhsAddr)) + v2plusscripts.DeployBatchBHS(e, common.HexToAddress(*bhsAddr)) case "batch-bhs-store": cmd := flag.NewFlagSet("batch-bhs-store", flag.ExitOnError) batchAddr := cmd.String("batch-bhs-address", "", "address of the batch bhs contract") @@ -467,14 +513,14 @@ func main() { helpers.PanicErr(err) fmt.Println("latest head number:", h.Number.String()) case "bhs-deploy": - deployBHS(e) + v2plusscripts.DeployBHS(e) case "coordinator-deploy": coordinatorDeployCmd := flag.NewFlagSet("coordinator-deploy", flag.ExitOnError) coordinatorDeployLinkAddress := coordinatorDeployCmd.String("link-address", "", "address of link token") coordinatorDeployBHSAddress := coordinatorDeployCmd.String("bhs-address", "", "address of bhs") coordinatorDeployLinkEthFeedAddress := coordinatorDeployCmd.String("link-eth-feed", "", "address of link-eth-feed") helpers.ParseArgs(coordinatorDeployCmd, os.Args[2:], "link-address", "bhs-address", "link-eth-feed") - deployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) + v2plusscripts.DeployCoordinator(e, *coordinatorDeployLinkAddress, *coordinatorDeployBHSAddress, *coordinatorDeployLinkEthFeedAddress) case "coordinator-get-config": cmd := flag.NewFlagSet("coordinator-get-config", flag.ExitOnError) coordinatorAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -483,7 +529,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - printCoordinatorConfig(coordinator) + v2plusscripts.PrintCoordinatorConfig(coordinator) case "coordinator-set-config": cmd := flag.NewFlagSet("coordinator-set-config", flag.ExitOnError) setConfigAddress := cmd.String("coordinator-address", "", "coordinator address") @@ -499,7 +545,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*setConfigAddress), e.Ec) helpers.PanicErr(err) - setCoordinatorConfig( + v2plusscripts.SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -526,7 +572,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - registerCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") @@ -658,7 +704,7 @@ func main() { helpers.PanicErr(err) fmt.Printf("Request config %+v Rw %+v Rid %+v\n", rc, rw, rid) case "deploy-universe": - deployUniverse(e) + v2plusscripts.DeployUniverseViaCLI(e) case "generate-proof-v2-plus": generateProofForV2Plus(e) case "eoa-consumer-deploy": @@ -667,7 +713,7 @@ func main() { consumerLinkAddress := consumerDeployCmd.String("link-address", "", "link-address") helpers.ParseArgs(consumerDeployCmd, os.Args[2:], "coordinator-address", "link-address", "key-hash") - eoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) + v2plusscripts.EoaDeployConsumer(e, *consumerCoordinator, *consumerLinkAddress) case "eoa-load-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-load-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") @@ -697,7 +743,7 @@ func main() { helpers.ParseArgs(createSubCmd, os.Args[2:], "coordinator-address") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaCreateSub(e, *coordinator) + v2plusscripts.EoaCreateSub(e, *coordinator) case "eoa-add-sub-consumer": addSubConsCmd := flag.NewFlagSet("eoa-add-sub-consumer", flag.ExitOnError) coordinatorAddress := addSubConsCmd.String("coordinator-address", "", "coordinator address") @@ -707,7 +753,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) parsedSubID := parseSubID(*subID) - eoaAddConsumerToSub(e, *coordinator, parsedSubID, *consumerAddress) + v2plusscripts.EoaAddConsumerToSub(e, *coordinator, parsedSubID, *consumerAddress) case "eoa-create-fund-authorize-sub": // Lets just treat the owner key as the EOA controlling the sub cfaSubCmd := flag.NewFlagSet("eoa-create-fund-authorize-sub", flag.ExitOnError) @@ -923,12 +969,9 @@ func main() { if !s { panic(fmt.Sprintf("failed to parse top up amount '%s'", *amountStr)) } - coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) - helpers.PanicErr(err) - e.Owner.Value = amount - tx, err := coordinator.FundSubscriptionWithNative(e.Owner, parseSubID(*subID)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) + parsedSubID := parseSubID(*subID) + + v2plusscripts.EoaFundSubWithNative(e, common.HexToAddress(*coordinatorAddress), parsedSubID, amount) case "eoa-fund-sub": fund := flag.NewFlagSet("eoa-fund-sub", flag.ExitOnError) coordinatorAddress := fund.String("coordinator-address", "", "coordinator address") @@ -943,7 +986,7 @@ func main() { coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaFundSubscription(e, *coordinator, *consumerLinkAddress, amount, parseSubID(*subID)) + v2plusscripts.EoaFundSubWithLink(e, *coordinator, *consumerLinkAddress, amount, parseSubID(*subID)) case "eoa-read": cmd := flag.NewFlagSet("eoa-read", flag.ExitOnError) consumerAddress := cmd.String("consumer", "", "consumer address") @@ -1076,7 +1119,7 @@ func main() { linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") coordinatorAddress := cmd.String("coordinator-address", "", "address of the vrf coordinator v2 contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address") - wrapperDeploy(e, + v2plusscripts.WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) @@ -1112,15 +1155,23 @@ func main() { wrapperPremiumPercentage := cmd.Uint("wrapper-premium-percentage", 25, "gas premium charged by wrapper") keyHash := cmd.String("key-hash", "", "the keyhash that wrapper requests should use") maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") - helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash") + fallbackWeiPerUnitLink := cmd.String("fallback-wei-per-unit-link", "", "the fallback wei per unit link") + stalenessSeconds := cmd.Uint("staleness-seconds", 86400, "the number of seconds of staleness to allow") + fulfillmentFlatFeeLinkPPM := cmd.Uint("fulfillment-flat-fee-link-ppm", 500, "the link flat fee in ppm to charge for fulfillment") + fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment") + helpers.ParseArgs(cmd, os.Args[2:], "wrapper-address", "key-hash", "fallback-wei-per-unit-link") - wrapperConfigure(e, + v2plusscripts.WrapperConfigure(e, common.HexToAddress(*wrapperAddress), *wrapperGasOverhead, *coordinatorGasOverhead, *wrapperPremiumPercentage, *keyHash, - *maxNumWords) + *maxNumWords, + decimal.RequireFromString(*fallbackWeiPerUnitLink).BigInt(), + uint32(*stalenessSeconds), + uint32(*fulfillmentFlatFeeLinkPPM), + uint32(*fulfillmentFlatFeeNativePPM)) case "wrapper-get-fulfillment-tx-size": cmd := flag.NewFlagSet("wrapper-get-fulfillment-tx-size", flag.ExitOnError) wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") @@ -1146,7 +1197,7 @@ func main() { wrapperAddress := cmd.String("wrapper-address", "", "address of the VRFV2Wrapper contract") helpers.ParseArgs(cmd, os.Args[2:], "link-address", "wrapper-address") - wrapperConsumerDeploy(e, + v2plusscripts.WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*wrapperAddress)) case "wrapper-consumer-request": @@ -1218,7 +1269,7 @@ func main() { helpers.ParseArgs(cmd, os.Args[2:]) _ = helpers.CalculateLatestBlockHeader(e, *blockNumber) case "wrapper-universe-deploy": - deployWrapperUniverse(e) + v2plusscripts.DeployWrapperUniverse(e) default: panic("unrecognized subcommand: " + os.Args[1]) } diff --git a/core/scripts/vrfv2plus/testnet/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go similarity index 60% rename from core/scripts/vrfv2plus/testnet/super_scripts.go rename to core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index f9efde8f148..f805e7b74f0 100644 --- a/core/scripts/vrfv2plus/testnet/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -1,4 +1,4 @@ -package main +package v2plusscripts import ( "bytes" @@ -6,6 +6,12 @@ import ( "encoding/hex" "flag" "fmt" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/jobs" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" + "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2plus_interface" "math/big" "os" "strings" @@ -18,7 +24,6 @@ import ( "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -30,46 +35,18 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" ) -const formattedVRFJob = ` -type = "vrf" -name = "vrf_v2_plus" -schemaVersion = 1 -coordinatorAddress = "%s" -batchCoordinatorAddress = "%s" -batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 -publicKey = "%s" -minIncomingConfirmations = 3 -evmChainID = "%d" -fromAddresses = ["%s"] -pollPeriod = "5s" -requestTimeout = "24h" -observationSource = """ -decode_log [type=ethabidecodelog - abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint256 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,bytes extraArgs,address indexed sender)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] -generate_proof [type=vrfv2plus - publicKey="$(jobSpec.publicKey)" - requestBlockHash="$(jobRun.logBlockHash)" - requestBlockNumber="$(jobRun.logBlockNumber)" - topics="$(jobRun.logTopics)"] -estimate_gas [type=estimategaslimit - to="%s" - multiplier="1.1" - data="$(generate_proof.output)"] -simulate_fulfillment [type=ethcall - to="%s" - gas="$(estimate_gas)" - gasPrice="$(jobSpec.maxGasPrice)" - extractRevertReason=true - contract="%s" - data="$(generate_proof.output)"] -decode_log->generate_proof->estimate_gas->simulate_fulfillment -""" -` - -func smokeTestVRF(e helpers.Environment) { +var coordinatorV2PlusABI = evmtypes.MustGetABI(vrf_coordinator_v2plus_interface.IVRFCoordinatorV2PlusInternalABI) + +type CoordinatorConfigV2Plus struct { + MinConfs *int + MaxGasLimit *int64 + StalenessSeconds *int64 + GasAfterPayment *int64 + FallbackWeiPerUnitLink *big.Int + FeeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig +} + +func SmokeTestVRF(e helpers.Environment) { smokeCmd := flag.NewFlagSet("smoke", flag.ExitOnError) // required flags @@ -120,7 +97,7 @@ func smokeTestVRF(e helpers.Environment) { var bhsContractAddress common.Address if len(*bhsAddressStr) == 0 { fmt.Println("\nDeploying BHS...") - bhsContractAddress = deployBHS(e) + bhsContractAddress = DeployBHS(e) } else { bhsContractAddress = common.HexToAddress(*bhsAddressStr) } @@ -128,7 +105,7 @@ func smokeTestVRF(e helpers.Environment) { var batchBHSAddress common.Address if len(*batchBHSAddressStr) == 0 { fmt.Println("\nDeploying Batch BHS...") - batchBHSAddress = deployBatchBHS(e, bhsContractAddress) + batchBHSAddress = DeployBatchBHS(e, bhsContractAddress) } else { batchBHSAddress = common.HexToAddress(*batchBHSAddressStr) } @@ -136,7 +113,7 @@ func smokeTestVRF(e helpers.Environment) { var coordinatorAddress common.Address if len(*coordinatorAddressStr) == 0 { fmt.Println("\nDeploying Coordinator...") - coordinatorAddress = deployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) + coordinatorAddress = DeployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) } else { coordinatorAddress = common.HexToAddress(*coordinatorAddressStr) } @@ -147,14 +124,14 @@ func smokeTestVRF(e helpers.Environment) { var batchCoordinatorAddress common.Address if len(*batchCoordinatorAddressStr) == 0 { fmt.Println("\nDeploying Batch Coordinator...") - batchCoordinatorAddress = deployBatchCoordinatorV2(e, coordinatorAddress) + batchCoordinatorAddress = DeployBatchCoordinatorV2(e, coordinatorAddress) } else { batchCoordinatorAddress = common.HexToAddress(*batchCoordinatorAddressStr) } if !*skipConfig { fmt.Println("\nSetting Coordinator Config...") - setCoordinatorConfig( + SetCoordinatorConfig( e, *coordinator, uint16(*minConfs), @@ -170,7 +147,7 @@ func smokeTestVRF(e helpers.Environment) { } fmt.Println("\nConfig set, getting current config from deployed contract...") - printCoordinatorConfig(coordinator) + PrintCoordinatorConfig(coordinator) // Generate compressed public key and key hash uncompressed, err := key.PublicKey.StringUncompressed() @@ -250,20 +227,20 @@ func smokeTestVRF(e helpers.Environment) { } fmt.Println("\nDeploying consumer...") - consumerAddress := eoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) + consumerAddress := EoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) fmt.Println("\nAdding subscription...") - eoaCreateSub(e, *coordinator) + EoaCreateSub(e, *coordinator) - subID := findSubscriptionID(e, coordinator) + subID := FindSubscriptionID(e, coordinator) helpers.PanicErr(err) fmt.Println("\nAdding consumer to subscription...") - eoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) + EoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, *coordinator, *linkAddress, subscriptionBalance, subID) + EoaFundSubWithLink(e, *coordinator, *linkAddress, subscriptionBalance, subID) } else { fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") } @@ -378,7 +355,7 @@ func smokeTestVRF(e helpers.Environment) { fmt.Println("\nfulfillment successful") } -func smokeTestBHS(e helpers.Environment) { +func SmokeTestBHS(e helpers.Environment) { smokeCmd := flag.NewFlagSet("smoke-bhs", flag.ExitOnError) // optional args @@ -390,7 +367,7 @@ func smokeTestBHS(e helpers.Environment) { var bhsContractAddress common.Address if len(*bhsAddress) == 0 { fmt.Println("\nDeploying BHS...") - bhsContractAddress = deployBHS(e) + bhsContractAddress = DeployBHS(e) } else { bhsContractAddress = common.HexToAddress(*bhsAddress) } @@ -398,7 +375,7 @@ func smokeTestBHS(e helpers.Environment) { var batchBHSContractAddress common.Address if len(*batchBHSAddress) == 0 { fmt.Println("\nDeploying Batch BHS...") - batchBHSContractAddress = deployBatchBHS(e, bhsContractAddress) + batchBHSContractAddress = DeployBatchBHS(e, bhsContractAddress) } else { batchBHSContractAddress = common.HexToAddress(*batchBHSAddress) } @@ -486,33 +463,106 @@ func sendTx(e helpers.Environment, to common.Address, data []byte) (*types.Recei e.ChainID, "send tx", signedTx.Hash().String(), "to", to.String()), signedTx.Hash() } -func deployUniverse(e helpers.Environment) { +func DeployUniverseViaCLI(e helpers.Environment) { deployCmd := flag.NewFlagSet("deploy-universe", flag.ExitOnError) // required flags - linkAddress := deployCmd.String("link-address", "", "address of link token") - linkEthAddress := deployCmd.String("link-eth-feed", "", "address of link eth feed") - subscriptionBalanceString := deployCmd.String("subscription-balance", "1e19", "amount to fund subscription") + linkAddress := *deployCmd.String("link-address", "", "address of link token") + linkEthAddress := *deployCmd.String("link-eth-feed", "", "address of link eth feed") + bhsContractAddressString := *deployCmd.String("bhs-address", "", "address of BHS contract") + batchBHSAddressString := *deployCmd.String("batch-bhs-address", "", "address of Batch BHS contract") + coordinatorAddressString := *deployCmd.String("coordinator-address", "", "address of VRF Coordinator contract") + batchCoordinatorAddressString := *deployCmd.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") + subscriptionBalanceJuelsString := deployCmd.String("subscription-balance", "1e19", "amount to fund subscription with Link token (Juels)") + subscriptionBalanceNativeWeiString := deployCmd.String("subscription-balance-native", "1e18", "amount to fund subscription with native token (Wei)") + + batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") registerKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") - registerKeyOracleAddress := deployCmd.String("oracle-address", "", "oracle sender address") - minConfs := deployCmd.Int("min-confs", 3, "min confs") - oracleFundingAmount := deployCmd.Int64("oracle-funding-amount", assets.GWei(100_000_000).Int64(), "amount to fund sending oracle") - maxGasLimit := deployCmd.Int64("max-gas-limit", 2.5e6, "max gas limit") - stalenessSeconds := deployCmd.Int64("staleness-seconds", 86400, "staleness in seconds") - gasAfterPayment := deployCmd.Int64("gas-after-payment", 33285, "gas after payment calculation") - flatFeeLinkPPM := deployCmd.Int64("flat-fee-link-ppm", 500, "fulfillment flat fee LINK ppm") - flatFeeEthPPM := deployCmd.Int64("flat-fee-eth-ppm", 500, "fulfillment flat fee ETH ppm") + vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") + minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") + nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") + maxGasLimit := deployCmd.Int64("max-gas-limit", constants.MaxGasLimit, "max gas limit") + stalenessSeconds := deployCmd.Int64("staleness-seconds", constants.StalenessSeconds, "staleness in seconds") + gasAfterPayment := deployCmd.Int64("gas-after-payment", constants.GasAfterPayment, "gas after payment calculation") + flatFeeLinkPPM := deployCmd.Int64("flat-fee-link-ppm", constants.FlatFeeLinkPPM, "fulfillment flat fee LINK ppm") + flatFeeEthPPM := deployCmd.Int64("flat-fee-eth-ppm", constants.FlatFeeNativePPM, "fulfillment flat fee ETH ppm") helpers.ParseArgs( - deployCmd, os.Args[2:], "uncompressed-pub-key", "oracle-address", + deployCmd, os.Args[2:], ) fallbackWeiPerUnitLink := decimal.RequireFromString(*fallbackWeiPerUnitLinkString).BigInt() - subscriptionBalance := decimal.RequireFromString(*subscriptionBalanceString).BigInt() + subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() + subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() + + feeConfig := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: uint32(*flatFeeLinkPPM), + FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), + } + + vrfPrimaryNodeSendingKeys := strings.Split(*vrfPrimaryNodeSendingKeysString, ",") + + nodesMap := make(map[string]model.Node) + + nodesMap[model.VRFPrimaryNodeName] = model.Node{ + SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), + SendingKeyFundingAmount: fundingAmount, + } + + bhsContractAddress := common.HexToAddress(bhsContractAddressString) + batchBHSAddress := common.HexToAddress(batchBHSAddressString) + coordinatorAddress := common.HexToAddress(coordinatorAddressString) + batchCoordinatorAddress := common.HexToAddress(batchCoordinatorAddressString) + + contractAddresses := model.ContractAddresses{ + LinkAddress: linkAddress, + LinkEthAddress: linkEthAddress, + BhsContractAddress: bhsContractAddress, + BatchBHSAddress: batchBHSAddress, + CoordinatorAddress: coordinatorAddress, + BatchCoordinatorAddress: batchCoordinatorAddress, + } + + coordinatorConfig := CoordinatorConfigV2Plus{ + MinConfs: minConfs, + MaxGasLimit: maxGasLimit, + StalenessSeconds: stalenessSeconds, + GasAfterPayment: gasAfterPayment, + FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, + FeeConfig: feeConfig, + } + VRFV2PlusDeployUniverse( + e, + subscriptionBalanceJuels, + subscriptionBalanceNativeWei, + registerKeyUncompressedPubKey, + contractAddresses, + coordinatorConfig, + *batchFulfillmentEnabled, + nodesMap, + ) + + vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] + fmt.Println("Funding node's sending keys...") + for _, sendingKey := range vrfPrimaryNode.SendingKeys { + helpers.FundNode(e, sendingKey.Address, vrfPrimaryNode.SendingKeyFundingAmount) + } +} + +func VRFV2PlusDeployUniverse(e helpers.Environment, + subscriptionBalanceJuels *big.Int, + subscriptionBalanceNativeWei *big.Int, + registerKeyUncompressedPubKey *string, + contractAddresses model.ContractAddresses, + coordinatorConfig CoordinatorConfigV2Plus, + batchFulfillmentEnabled bool, + nodesMap map[string]model.Node, +) model.JobSpecs { // Put key in ECDSA format if strings.HasPrefix(*registerKeyUncompressedPubKey, "0x") { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) @@ -536,55 +586,60 @@ func deployUniverse(e helpers.Environment) { keyHash, err := newPK.Hash() helpers.PanicErr(err) - if len(*linkAddress) == 0 { + if len(contractAddresses.LinkAddress) == 0 { fmt.Println("\nDeploying LINK Token...") - address := helpers.DeployLinkToken(e).String() - linkAddress = &address + contractAddresses.LinkAddress = helpers.DeployLinkToken(e).String() } - if len(*linkEthAddress) == 0 { + if len(contractAddresses.LinkEthAddress) == 0 { fmt.Println("\nDeploying LINK/ETH Feed...") - address := helpers.DeployLinkEthFeed(e, *linkAddress, fallbackWeiPerUnitLink).String() - linkEthAddress = &address + contractAddresses.LinkEthAddress = helpers.DeployLinkEthFeed(e, contractAddresses.LinkAddress, coordinatorConfig.FallbackWeiPerUnitLink).String() } - fmt.Println("\nDeploying BHS...") - bhsContractAddress := deployBHS(e) + if contractAddresses.BhsContractAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying BHS...") + contractAddresses.BhsContractAddress = DeployBHS(e) + } - fmt.Println("\nDeploying Batch BHS...") - batchBHSAddress := deployBatchBHS(e, bhsContractAddress) + if contractAddresses.BatchBHSAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Batch BHS...") + contractAddresses.BatchBHSAddress = DeployBatchBHS(e, contractAddresses.BhsContractAddress) + } - var coordinatorAddress common.Address - fmt.Println("\nDeploying Coordinator...") - coordinatorAddress = deployCoordinator(e, *linkAddress, bhsContractAddress.String(), *linkEthAddress) + if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Coordinator...") + contractAddresses.CoordinatorAddress = DeployCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + } - coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(coordinatorAddress, e.Ec) + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(contractAddresses.CoordinatorAddress, e.Ec) helpers.PanicErr(err) - fmt.Println("\nDeploying Batch Coordinator...") - batchCoordinatorAddress := deployBatchCoordinatorV2(e, coordinatorAddress) + if contractAddresses.BatchCoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Batch Coordinator...") + contractAddresses.BatchCoordinatorAddress = DeployBatchCoordinatorV2(e, contractAddresses.CoordinatorAddress) + } fmt.Println("\nSetting Coordinator Config...") - setCoordinatorConfig( + SetCoordinatorConfig( e, *coordinator, - uint16(*minConfs), - uint32(*maxGasLimit), - uint32(*stalenessSeconds), - uint32(*gasAfterPayment), - fallbackWeiPerUnitLink, - vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: uint32(*flatFeeLinkPPM), - FulfillmentFlatFeeNativePPM: uint32(*flatFeeEthPPM), - }, + uint16(*coordinatorConfig.MinConfs), + uint32(*coordinatorConfig.MaxGasLimit), + uint32(*coordinatorConfig.StalenessSeconds), + uint32(*coordinatorConfig.GasAfterPayment), + coordinatorConfig.FallbackWeiPerUnitLink, + coordinatorConfig.FeeConfig, ) fmt.Println("\nConfig set, getting current config from deployed contract...") - printCoordinatorConfig(coordinator) + PrintCoordinatorConfig(coordinator) - if len(*registerKeyUncompressedPubKey) > 0 && len(*registerKeyOracleAddress) > 0 { + if len(*registerKeyUncompressedPubKey) > 0 { fmt.Println("\nRegistering proving key...") - registerCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + + //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able + // easily withdraw funds from Coordinator contract back to EOA account + RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, e.Owner.From.String()) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -595,22 +650,28 @@ func deployUniverse(e helpers.Environment) { } fmt.Println("\nDeploying consumer...") - consumerAddress := eoaDeployConsumer(e, coordinatorAddress.String(), *linkAddress) + consumerAddress := EoaV2PlusLoadTestConsumerWithMetricsDeploy(e, contractAddresses.CoordinatorAddress.String()) fmt.Println("\nAdding subscription...") - eoaCreateSub(e, *coordinator) + EoaCreateSub(e, *coordinator) - subID := findSubscriptionID(e, coordinator) + subID := FindSubscriptionID(e, coordinator) helpers.PanicErr(err) fmt.Println("\nAdding consumer to subscription...") - eoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) + EoaAddConsumerToSub(e, *coordinator, subID, consumerAddress.String()) - if subscriptionBalance.Cmp(big.NewInt(0)) > 0 { - fmt.Println("\nFunding subscription with", subscriptionBalance, "juels...") - eoaFundSubscription(e, *coordinator, *linkAddress, subscriptionBalance, subID) + if subscriptionBalanceJuels.Cmp(big.NewInt(0)) > 0 { + fmt.Println("\nFunding subscription with Link Token.", subscriptionBalanceJuels, "juels...") + EoaFundSubWithLink(e, *coordinator, contractAddresses.LinkAddress, subscriptionBalanceJuels, subID) } else { - fmt.Println("Subscription", subID, "NOT getting funded. You must fund the subscription in order to use it!") + fmt.Println("Subscription", subID, "NOT getting funded with Link Token. You must fund the subscription in order to use it!") + } + if subscriptionBalanceNativeWei.Cmp(big.NewInt(0)) > 0 { + fmt.Println("\nFunding subscription with Native Token.", subscriptionBalanceNativeWei, "wei...") + EoaFundSubWithNative(e, coordinator.Address(), subID, subscriptionBalanceNativeWei) + } else { + fmt.Println("Subscription", subID, "NOT getting funded with Native Token. You must fund the subscription in order to use it!") } fmt.Println("\nSubscribed and (possibly) funded, retrieving subscription from deployed contract...") @@ -618,43 +679,95 @@ func deployUniverse(e helpers.Environment) { helpers.PanicErr(err) fmt.Printf("Subscription %+v\n", s) - if len(*registerKeyOracleAddress) > 0 && *oracleFundingAmount > 0 { - fmt.Println("\nFunding oracle...") - helpers.FundNodes(e, []string{*registerKeyOracleAddress}, big.NewInt(*oracleFundingAmount)) - } - - formattedJobSpec := fmt.Sprintf( - formattedVRFJob, - coordinatorAddress, - batchCoordinatorAddress, - false, - compressedPkHex, - e.ChainID, - *registerKeyOracleAddress, - coordinatorAddress, - coordinatorAddress, - coordinatorAddress, + formattedVrfV2PlusPrimaryJobSpec := fmt.Sprintf( + jobs.VRFV2PlusJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + batchFulfillmentEnabled, //batchFulfillmentEnabled + compressedPkHex, //publicKey + *coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + contractAddresses.CoordinatorAddress, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0].Address, + contractAddresses.CoordinatorAddress, + contractAddresses.CoordinatorAddress, + ) + + formattedVrfV2PlusBackupJobSpec := fmt.Sprintf( + jobs.VRFV2PlusJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + batchFulfillmentEnabled, //batchFulfillmentEnabled + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID + strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + contractAddresses.CoordinatorAddress, + nodesMap[model.VRFPrimaryNodeName].SendingKeys[0], + contractAddresses.CoordinatorAddress, + contractAddresses.CoordinatorAddress, + ) + + formattedBHSJobSpec := fmt.Sprintf( + jobs.BHSJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + 30, //waitBlocks + 200, //lookbackBlocks + contractAddresses.BhsContractAddress, //bhs address + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSNodeName].SendingKeys), "\",\""), //sending addresses + ) + + formattedBHSBackupJobSpec := fmt.Sprintf( + jobs.BHSJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + 100, //waitBlocks + 200, //lookbackBlocks + contractAddresses.BhsContractAddress, //bhs adreess + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHSBackupNodeName].SendingKeys), "\",\""), //sending addresses + ) + + formattedBHFJobSpec := fmt.Sprintf( + jobs.BHFJobFormatted, + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BhsContractAddress, //bhs adreess + contractAddresses.BatchBHSAddress, //batchBHS + e.ChainID, //chain id + strings.Join(util.MapToAddressArr(nodesMap[model.BHFNodeName].SendingKeys), "\",\""), //sending addresses ) fmt.Println( "\nDeployment complete.", - "\nLINK Token contract address:", *linkAddress, - "\nLINK/ETH Feed contract address:", *linkEthAddress, - "\nBlockhash Store contract address:", bhsContractAddress, - "\nBatch Blockhash Store contract address:", batchBHSAddress, - "\nVRF Coordinator Address:", coordinatorAddress, - "\nBatch VRF Coordinator Address:", batchCoordinatorAddress, + "\nLINK Token contract address:", contractAddresses.LinkAddress, + "\nLINK/ETH Feed contract address:", contractAddresses.LinkEthAddress, + "\nBlockhash Store contract address:", contractAddresses.BhsContractAddress, + "\nBatch Blockhash Store contract address:", contractAddresses.BatchBHSAddress, + "\nVRF Coordinator Address:", contractAddresses.CoordinatorAddress, + "\nBatch VRF Coordinator Address:", contractAddresses.BatchCoordinatorAddress, "\nVRF Consumer Address:", consumerAddress, "\nVRF Subscription Id:", subID, - "\nVRF Subscription Balance:", *subscriptionBalanceString, + "\nVRF Subscription LINK Balance:", *subscriptionBalanceJuels, + "\nVRF Subscription Native Balance:", *subscriptionBalanceNativeWei, "\nPossible VRF Request command: ", - fmt.Sprintf("go run . eoa-request --consumer-address %s --sub-id %d --key-hash %s", consumerAddress, subID, keyHash), + fmt.Sprintf("go run . eoa-load-test-request-with-metrics --consumer-address=%s --sub-id=%d --key-hash=%s --request-confirmations %d --requests 1 --runs 1 --cb-gas-limit 1_000_000", consumerAddress, subID, keyHash, *coordinatorConfig.MinConfs), + "\nRetrieve Request Status: ", + fmt.Sprintf("go run . eoa-load-test-read-metrics --consumer-address=%s", consumerAddress), "\nA node can now be configured to run a VRF job with the below job spec :\n", - formattedJobSpec, + formattedVrfV2PlusPrimaryJobSpec, ) + + return model.JobSpecs{ + VRFPrimaryNode: formattedVrfV2PlusPrimaryJobSpec, + VRFBackupyNode: formattedVrfV2PlusBackupJobSpec, + BHSNode: formattedBHSJobSpec, + BHSBackupNode: formattedBHSBackupJobSpec, + BHFNode: formattedBHFJobSpec, + } } -func deployWrapperUniverse(e helpers.Environment) { +func DeployWrapperUniverse(e helpers.Environment) { cmd := flag.NewFlagSet("wrapper-universe-deploy", flag.ExitOnError) linkAddress := cmd.String("link-address", "", "address of link token") linkETHFeedAddress := cmd.String("link-eth-feed", "", "address of link-eth-feed") @@ -666,34 +779,43 @@ func deployWrapperUniverse(e helpers.Environment) { maxNumWords := cmd.Uint("max-num-words", 10, "the keyhash that wrapper requests should use") subFunding := cmd.String("sub-funding", "10000000000000000000", "amount to fund the subscription with") consumerFunding := cmd.String("consumer-funding", "10000000000000000000", "amount to fund the consumer with") - helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address", "key-hash") + fallbackWeiPerUnitLink := cmd.String("fallback-wei-per-unit-link", "", "the fallback wei per unit link") + stalenessSeconds := cmd.Uint("staleness-seconds", 86400, "the number of seconds of staleness to allow") + fulfillmentFlatFeeLinkPPM := cmd.Uint("fulfillment-flat-fee-link-ppm", 500, "the link flat fee in ppm to charge for fulfillment") + fulfillmentFlatFeeNativePPM := cmd.Uint("fulfillment-flat-fee-native-ppm", 500, "the native flat fee in ppm to charge for fulfillment") + helpers.ParseArgs(cmd, os.Args[2:], "link-address", "link-eth-feed", "coordinator-address", "key-hash", "fallback-wei-per-unit-link") amount, s := big.NewInt(0).SetString(*subFunding, 10) if !s { panic(fmt.Sprintf("failed to parse top up amount '%s'", *subFunding)) } - wrapper, subID := wrapperDeploy(e, + wrapper, subID := WrapperDeploy(e, common.HexToAddress(*linkAddress), common.HexToAddress(*linkETHFeedAddress), common.HexToAddress(*coordinatorAddress)) - wrapperConfigure(e, + WrapperConfigure(e, wrapper, *wrapperGasOverhead, *coordinatorGasOverhead, *wrapperPremiumPercentage, *keyHash, - *maxNumWords) + *maxNumWords, + decimal.RequireFromString(*fallbackWeiPerUnitLink).BigInt(), + uint32(*stalenessSeconds), + uint32(*fulfillmentFlatFeeLinkPPM), + uint32(*fulfillmentFlatFeeNativePPM), + ) - consumer := wrapperConsumerDeploy(e, + consumer := WrapperConsumerDeploy(e, common.HexToAddress(*linkAddress), wrapper) coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - eoaFundSubscription(e, *coordinator, *linkAddress, amount, subID) + EoaFundSubWithLink(e, *coordinator, *linkAddress, amount, subID) link, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) helpers.PanicErr(err) diff --git a/core/scripts/vrfv2plus/testnet/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go similarity index 76% rename from core/scripts/vrfv2plus/testnet/util.go rename to core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index 904a3f6ba4f..ebe881a9951 100644 --- a/core/scripts/vrfv2plus/testnet/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -1,9 +1,10 @@ -package main +package v2plusscripts import ( "context" "encoding/hex" "fmt" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -22,19 +23,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -func deployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { +func DeployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { _, tx, _, err := blockhash_store.DeployBlockhashStore(e.Owner, e.Ec) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployBatchBHS(e helpers.Environment, bhsAddress common.Address) (batchBHSAddress common.Address) { +func DeployBatchBHS(e helpers.Environment, bhsAddress common.Address) (batchBHSAddress common.Address) { _, tx, _, err := batch_blockhash_store.DeployBatchBlockhashStore(e.Owner, e.Ec, bhsAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func deployCoordinator( +func DeployCoordinator( e helpers.Environment, linkAddress string, bhsAddress string, @@ -58,27 +59,31 @@ func deployCoordinator( return coordinatorAddress } -func deployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { +func DeployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { _, tx, _, err := batch_vrf_coordinator_v2plus.DeployBatchVRFCoordinatorV2Plus(e.Owner, e.Ec, coordinatorAddress) helpers.PanicErr(err) return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func eoaAddConsumerToSub(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, subID *big.Int, consumerAddress string) { +func EoaAddConsumerToSub( + e helpers.Environment, + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, + subID *big.Int, + consumerAddress string, +) { txadd, err := coordinator.AddConsumer(e.Owner, subID, common.HexToAddress(consumerAddress)) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, txadd, e.ChainID) } -func eoaCreateSub(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25) { +func EoaCreateSub(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25) { tx, err := coordinator.CreateSubscription(e.Owner) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } // returns subscription ID that belongs to the given owner. Returns result found first -func findSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) *big.Int { +func FindSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) *big.Int { // Use most recent 500 blocks as search window. head, err := e.Ec.BlockNumber(context.Background()) helpers.PanicErr(err) @@ -95,7 +100,7 @@ func findSubscriptionID(e helpers.Environment, coordinator *vrf_coordinator_v2_5 return subscriptionIterator.Event.SubId } -func eoaDeployConsumer(e helpers.Environment, +func EoaDeployConsumer(e helpers.Environment, coordinatorAddress string, linkAddress string) ( consumerAddress common.Address) { @@ -108,13 +113,17 @@ func eoaDeployConsumer(e helpers.Environment, return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } -func eoaFundSubscription(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, linkAddress string, amount, subID *big.Int) { +func EoaFundSubWithLink( + e helpers.Environment, + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, + linkAddress string, amount, + subID *big.Int, +) { linkToken, err := link_token_interface.NewLinkToken(common.HexToAddress(linkAddress), e.Ec) helpers.PanicErr(err) bal, err := linkToken.BalanceOf(nil, e.Owner.From) helpers.PanicErr(err) - fmt.Println("Initial account balance:", bal, e.Owner.From.String(), "Funding amount:", amount.String()) + fmt.Println("Initial account balance (Juels):", bal, e.Owner.From.String(), "Funding amount:", amount.String()) b, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) helpers.PanicErr(err) tx, err := linkToken.TransferAndCall(e.Owner, coordinator.Address(), amount, b) @@ -122,7 +131,16 @@ func eoaFundSubscription(e helpers.Environment, helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("sub ID: %d", subID)) } -func printCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) { +func EoaFundSubWithNative(e helpers.Environment, coordinatorAddress common.Address, subID *big.Int, amount *big.Int) { + coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(coordinatorAddress, e.Ec) + helpers.PanicErr(err) + e.Owner.Value = amount + tx, err := coordinator.FundSubscriptionWithNative(e.Owner, subID) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) +} + +func PrintCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) { cfg, err := coordinator.SConfig(nil) helpers.PanicErr(err) @@ -133,7 +151,7 @@ func printCoordinatorConfig(coordinator *vrf_coordinator_v2_5.VRFCoordinatorV25) fmt.Printf("Coordinator fee config: %+v\n", feeConfig) } -func setCoordinatorConfig( +func SetCoordinatorConfig( e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, minConfs uint16, @@ -156,7 +174,7 @@ func setCoordinatorConfig( helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } -func registerCoordinatorProvingKey(e helpers.Environment, +func RegisterCoordinatorProvingKey(e helpers.Environment, coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string, oracleAddress string) { pubBytes, err := hex.DecodeString(uncompressed) helpers.PanicErr(err) @@ -176,7 +194,7 @@ func registerCoordinatorProvingKey(e helpers.Environment, ) } -func wrapperDeploy( +func WrapperDeploy( e helpers.Environment, link, linkEthFeed, coordinator common.Address, ) (common.Address, *big.Int) { @@ -199,12 +217,16 @@ func wrapperDeploy( return address, subID } -func wrapperConfigure( +func WrapperConfigure( e helpers.Environment, wrapperAddress common.Address, wrapperGasOverhead, coordinatorGasOverhead, premiumPercentage uint, keyHash string, maxNumWords uint, + fallbackWeiPerUnitLink *big.Int, + stalenessSeconds uint32, + fulfillmentFlatFeeLinkPPM uint32, + fulfillmentFlatFeeNativePPM uint32, ) { wrapper, err := vrfv2plus_wrapper.NewVRFV2PlusWrapper(wrapperAddress, e.Ec) helpers.PanicErr(err) @@ -215,12 +237,18 @@ func wrapperConfigure( uint32(coordinatorGasOverhead), uint8(premiumPercentage), common.HexToHash(keyHash), - uint8(maxNumWords)) + uint8(maxNumWords), + stalenessSeconds, + fallbackWeiPerUnitLink, + fulfillmentFlatFeeLinkPPM, + fulfillmentFlatFeeNativePPM, + ) + helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } -func wrapperConsumerDeploy( +func WrapperConsumerDeploy( e helpers.Environment, link, wrapper common.Address, ) common.Address { @@ -233,3 +261,13 @@ func wrapperConsumerDeploy( fmt.Printf("VRFV2WrapperConsumerExample address: %s\n", address) return address } + +func EoaV2PlusLoadTestConsumerWithMetricsDeploy(e helpers.Environment, consumerCoordinator string) (consumerAddress common.Address) { + _, tx, _, err := vrf_v2plus_load_test_with_metrics.DeployVRFV2PlusLoadTestWithMetrics( + e.Owner, + e.Ec, + common.HexToAddress(consumerCoordinator), + ) + helpers.PanicErr(err) + return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) +} diff --git a/core/services/blockhashstore/batch_bhs.go b/core/services/blockhashstore/batch_bhs.go index 96e5784a8cd..d8381ff6231 100644 --- a/core/services/blockhashstore/batch_bhs.go +++ b/core/services/blockhashstore/batch_bhs.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type batchBHSConfig interface { @@ -66,13 +65,13 @@ func (b *BatchBlockhashStore) StoreVerifyHeader(ctx context.Context, blockNumber return errors.Wrap(err, "packing args") } - _, err = b.txm.CreateTransaction(txmgr.TxRequest{ + _, err = b.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: b.batchbhs.Address(), EncodedPayload: payload, FeeLimit: b.config.LimitDefault(), Strategy: txmgrcommon.NewSendEveryStrategy(), - }, pg.WithParentCtx(ctx)) + }) if err != nil { return errors.Wrap(err, "creating transaction") diff --git a/core/services/blockhashstore/bhs.go b/core/services/blockhashstore/bhs.go index 70a9c77669c..3de00f64590 100644 --- a/core/services/blockhashstore/bhs.go +++ b/core/services/blockhashstore/bhs.go @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/trusted_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) var _ BHS = &BulletproofBHS{} @@ -97,7 +96,7 @@ func (c *BulletproofBHS) Store(ctx context.Context, blockNum uint64) error { return errors.Wrap(err, "getting next from address") } - _, err = c.txm.CreateTransaction(txmgr.TxRequest{ + _, err = c.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: c.bhs.Address(), EncodedPayload: payload, @@ -106,7 +105,7 @@ func (c *BulletproofBHS) Store(ctx context.Context, blockNum uint64) error { // Set a queue size of 256. At most we store the blockhash of every block, and only the // latest 256 can possibly be stored. Strategy: txmgrcommon.NewQueueingTxStrategy(c.jobID, 256, c.dbConfig.DefaultQueryTimeout()), - }, pg.WithParentCtx(ctx)) + }) if err != nil { return errors.Wrap(err, "creating transaction") } @@ -137,14 +136,14 @@ func (c *BulletproofBHS) StoreTrusted( if err != nil { return errors.Wrap(err, "getting next from address") } - _, err = c.txm.CreateTransaction(txmgr.TxRequest{ + _, err = c.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: c.trustedBHS.Address(), EncodedPayload: payload, FeeLimit: c.config.LimitDefault(), Strategy: txmgrcommon.NewSendEveryStrategy(), - }, pg.WithParentCtx(ctx)) + }) if err != nil { return errors.Wrap(err, "creating transaction") } @@ -192,13 +191,13 @@ func (c *BulletproofBHS) StoreEarliest(ctx context.Context) error { return errors.Wrap(err, "getting next from address") } - _, err = c.txm.CreateTransaction(txmgr.TxRequest{ + _, err = c.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: c.bhs.Address(), EncodedPayload: payload, FeeLimit: c.config.LimitDefault(), Strategy: txmgrcommon.NewSendEveryStrategy(), - }, pg.WithParentCtx(ctx)) + }) if err != nil { return errors.Wrap(err, "creating transaction") } diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 79494ea41f6..ed32b3ab49f 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -58,13 +58,13 @@ func TestStoreRotatesFromAddresses(t *testing.T) { ) require.NoError(t, err) - txm.On("CreateTransaction", mock.MatchedBy(func(tx txmgr.TxRequest) bool { + txm.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.FromAddress.String() == k1.Address.String() - }), mock.Anything).Once().Return(txmgr.Tx{}, nil) + })).Once().Return(txmgr.Tx{}, nil) - txm.On("CreateTransaction", mock.MatchedBy(func(tx txmgr.TxRequest) bool { + txm.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.FromAddress.String() == k2.Address.String() - }), mock.Anything).Once().Return(txmgr.Tx{}, nil) + })).Once().Return(txmgr.Tx{}, nil) // store 2 blocks err = bhs.Store(context.Background(), 1) diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index ccd4d3463f5..90819f27a1d 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -50,7 +50,7 @@ func (d *Delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if jb.BlockhashStoreSpec == nil { return nil, errors.Errorf( "blockhashstore.Delegate expects a BlockhashStoreSpec to be present, got %+v", jb) diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 3060f617876..582492105e0 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -55,7 +55,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { }) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - sendingKey, _ := cltest.MustAddRandomKeyToKeystore(t, kst) + sendingKey, _ := cltest.MustInsertRandomKey(t, kst) lp := &mocklp.LogPoller{} lp.On("RegisterFilter", mock.Anything).Return(nil) lp.On("LatestBlock", mock.Anything, mock.Anything).Return(int64(0), nil) diff --git a/core/services/blockhashstore/mocks/bhs.go b/core/services/blockhashstore/mocks/bhs.go index bf01e80ffdd..51ddca46a0d 100644 --- a/core/services/blockhashstore/mocks/bhs.go +++ b/core/services/blockhashstore/mocks/bhs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -95,13 +95,12 @@ func (_m *BHS) StoreTrusted(ctx context.Context, blockNums []uint64, blockhashes return r0 } -type mockConstructorTestingTNewBHS interface { +// NewBHS creates a new instance of BHS. 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 NewBHS(t interface { mock.TestingT Cleanup(func()) -} - -// NewBHS creates a new instance of BHS. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBHS(t mockConstructorTestingTNewBHS) *BHS { +}) *BHS { mock := &BHS{} mock.Mock.Test(t) diff --git a/core/services/blockhashstore/mocks/timer.go b/core/services/blockhashstore/mocks/timer.go index 722cd35f271..c116163a3df 100644 --- a/core/services/blockhashstore/mocks/timer.go +++ b/core/services/blockhashstore/mocks/timer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -29,13 +29,12 @@ func (_m *Timer) After(d time.Duration) <-chan time.Time { return r0 } -type mockConstructorTestingTNewTimer interface { +// NewTimer creates a new instance of Timer. 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 NewTimer(t interface { mock.TestingT Cleanup(func()) -} - -// NewTimer creates a new instance of Timer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTimer(t mockConstructorTestingTNewTimer) *Timer { +}) *Timer { mock := &Timer{} mock.Mock.Test(t) diff --git a/core/services/blockhashstore/test_util.go b/core/services/blockhashstore/test_util.go index 6b7c3836650..0ab07931295 100644 --- a/core/services/blockhashstore/test_util.go +++ b/core/services/blockhashstore/test_util.go @@ -2,11 +2,11 @@ package blockhashstore import ( "context" + "crypto/rand" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "golang.org/x/exp/rand" ) type TestCoordinator struct { diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 2f37991f741..02ab34821f6 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -48,7 +48,7 @@ func (d *Delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if jb.BlockHeaderFeederSpec == nil { return nil, errors.Errorf("Delegate expects a BlockHeaderFeederSpec to be present, got %+v", jb) } diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 814c8a1c10b..354f0479042 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" @@ -47,7 +48,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" @@ -69,7 +69,6 @@ type Application interface { GetConfig() GeneralConfig SetLogLevel(lvl zapcore.Level) error GetKeyStore() keystore.Master - GetEventBroadcaster() pg.EventBroadcaster WakeSessionReaper() GetWebAuthnConfiguration() sessions.WebAuthnConfiguration @@ -184,7 +183,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { // we need to initialize in case we serve OCR2 LOOPs loopRegistry := opts.LoopRegistry if loopRegistry == nil { - loopRegistry = plugins.NewLoopRegistry(globalLogger) + loopRegistry = plugins.NewLoopRegistry(globalLogger, opts.Config.Tracing()) } // If the audit logger is enabled @@ -217,24 +216,8 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Info("Nurse service (automatic pprof profiling) is disabled") } - telemetryIngressClient := synchronization.TelemetryIngressClient(&synchronization.NoopTelemetryIngressClient{}) - telemetryIngressBatchClient := synchronization.TelemetryIngressBatchClient(&synchronization.NoopTelemetryIngressBatchClient{}) - monitoringEndpointGen := telemetry.MonitoringEndpointGenerator(&telemetry.NoopAgent{}) - - ticfg := cfg.TelemetryIngress() - if ticfg.URL() != nil { - if ticfg.UseBatchSend() { - telemetryIngressBatchClient = synchronization.NewTelemetryIngressBatchClient(ticfg.URL(), - ticfg.ServerPubKey(), keyStore.CSA(), ticfg.Logging(), globalLogger, ticfg.BufferSize(), ticfg.MaxBatchSize(), ticfg.SendInterval(), ticfg.SendTimeout(), ticfg.UniConn()) - monitoringEndpointGen = telemetry.NewIngressAgentBatchWrapper(telemetryIngressBatchClient) - - } else { - telemetryIngressClient = synchronization.NewTelemetryIngressClient(ticfg.URL(), - ticfg.ServerPubKey(), keyStore.CSA(), ticfg.Logging(), globalLogger, ticfg.BufferSize()) - monitoringEndpointGen = telemetry.NewIngressAgentWrapper(telemetryIngressClient) - } - } - srvcs = append(srvcs, telemetryIngressClient, telemetryIngressBatchClient) + telemetryManager := telemetry.NewManager(cfg.TelemetryIngress(), keyStore.CSA(), globalLogger) + srvcs = append(srvcs, telemetryManager) backupCfg := cfg.Database().Backup() if backupCfg.Mode() != config.DatabaseBackupModeNone && backupCfg.Frequency() > 0 { @@ -359,7 +342,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { keyStore, pipelineRunner, peerWrapper, - monitoringEndpointGen, + telemetryManager, legacyEVMChains, globalLogger, cfg.Database(), @@ -379,7 +362,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { mercuryORM, pipelineRunner, peerWrapper, - monitoringEndpointGen, + telemetryManager, legacyEVMChains, globalLogger, ocr2DelegateConfig, @@ -404,7 +387,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Debug("Off-chain reporting v2 disabled") } - healthChecker := services.NewChecker() + healthChecker := relayservices.NewChecker() var lbs []utils.DependentAwaiter for _, c := range legacyEVMChains.Slice() { diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 5578f8c0453..26e2d539bac 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -1,25 +1,24 @@ package chainlink import ( - "fmt" - "errors" + "fmt" "go.uber.org/multierr" gotoml "github.com/pelletier/go-toml/v2" - "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" + stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) // Config is the root type used for TOML configuration. @@ -39,9 +38,9 @@ type Config struct { Cosmos cosmos.CosmosConfigs `toml:",omitempty"` - Solana solana.SolanaConfigs `toml:",omitempty"` + Solana solana.TOMLConfigs `toml:",omitempty"` - Starknet starknet.StarknetConfigs `toml:",omitempty"` + Starknet stkcfg.TOMLConfigs `toml:",omitempty"` } // TOMLString returns a TOML encoded string. @@ -53,6 +52,50 @@ func (c *Config) TOMLString() (string, error) { return string(b), nil } +// deprecationWarnings returns an error if the Config contains deprecated fields. +// This is typically used before defaults have been applied, with input from the user. +func (c *Config) deprecationWarnings() (err error) { + if c.P2P.V1 != (toml.P2PV1{}) { + err = multierr.Append(err, config.ErrDeprecated{Name: "P2P.V1"}) + var err2 error + if c.P2P.V1.AnnounceIP != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnounceIP"}) + } + if c.P2P.V1.AnnouncePort != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnouncePort"}) + } + if c.P2P.V1.BootstrapCheckInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "BootstrapCheckInterval"}) + } + if c.P2P.V1.DefaultBootstrapPeers != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DefaultBootstrapPeers"}) + } + if c.P2P.V1.DHTAnnouncementCounterUserPrefix != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTAnnouncementCounterUserPrefix"}) + } + if c.P2P.V1.DHTLookupInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTLookupInterval"}) + } + if c.P2P.V1.ListenIP != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenIP"}) + } + if c.P2P.V1.ListenPort != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenPort"}) + } + if c.P2P.V1.NewStreamTimeout != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "NewStreamTimeout"}) + } + if c.P2P.V1.PeerstoreWriteInterval != nil { + err2 = multierr.Append(err2, config.ErrDeprecated{Name: "PeerstoreWriteInterval"}) + } + err2 = config.NamedMultiErrorList(err2, "P2P.V1") + err = multierr.Append(err, err2) + } + return +} + +// Validate returns an error if the Config is not valid for use, as-is. +// This is typically used after defaults have been applied. func (c *Config) Validate() error { if err := config.Validate(c); err != nil { return fmt.Errorf("invalid configuration: %w", err) @@ -83,14 +126,14 @@ func (c *Config) setDefaults() { for i := range c.Solana { if c.Solana[i] == nil { - c.Solana[i] = new(solana.SolanaConfig) + c.Solana[i] = new(solana.TOMLConfig) } c.Solana[i].Chain.SetDefaults() } for i := range c.Starknet { if c.Starknet[i] == nil { - c.Starknet[i] = new(starknet.StarknetConfig) + c.Starknet[i] = new(stkcfg.TOMLConfig) } c.Starknet[i].Chain.SetDefaults() } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 688215c6978..6243146e91e 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -3,7 +3,6 @@ package chainlink import ( _ "embed" "fmt" - "net/url" "os" "path/filepath" "strings" @@ -16,10 +15,11 @@ import ( ocrnetworking "github.com/smartcontractkit/libocr/networking" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" + starknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/env" @@ -35,11 +35,13 @@ import ( type generalConfig struct { inputTOML string // user input, normalized via de/re-serialization effectiveTOML string // with default values included - secretsTOML string // with env overdies includes, redacted + secretsTOML string // with env overrides includes, redacted c *Config // all fields non-nil (unless the legacy method signature return a pointer) secrets *Secrets + warning error // warnings about inputTOML, e.g. deprecated fields + logLevelDefault zapcore.Level appIDOnce sync.Once @@ -123,7 +125,7 @@ func (o *GeneralConfigOpts) parseSecrets(secrets string) error { return nil } -// New returns a coreconfig.GeneralConfig for the given options. +// New returns a GeneralConfig for the given options. func (o GeneralConfigOpts) New() (GeneralConfig, error) { err := o.parse() if err != nil { @@ -135,6 +137,8 @@ func (o GeneralConfigOpts) New() (GeneralConfig, error) { return nil, err } + _, warning := utils.MultiErrorList(o.Config.deprecationWarnings()) + o.Config.setDefaults() if !o.SkipEnv { err = o.Secrets.setEnv() @@ -163,6 +167,7 @@ func (o GeneralConfigOpts) New() (GeneralConfig, error) { secretsTOML: secrets, c: &o.Config, secrets: &o.Secrets, + warning: warning, } if lvl := o.Config.Log.Level; lvl != nil { cfg.logLevelDefault = zapcore.Level(*lvl) @@ -198,11 +203,11 @@ func (g *generalConfig) CosmosConfigs() cosmos.CosmosConfigs { return g.c.Cosmos } -func (g *generalConfig) SolanaConfigs() solana.SolanaConfigs { +func (g *generalConfig) SolanaConfigs() solana.TOMLConfigs { return g.c.Solana } -func (g *generalConfig) StarknetConfigs() starknet.StarknetConfigs { +func (g *generalConfig) StarknetConfigs() starknet.TOMLConfigs { return g.c.Starknet } @@ -253,10 +258,13 @@ func validateEnv() (err error) { return } -func (g *generalConfig) LogConfiguration(log coreconfig.LogfFn) { +func (g *generalConfig) LogConfiguration(log, warn coreconfig.LogfFn) { log("# Secrets:\n%s\n", g.secretsTOML) log("# Input Configuration:\n%s\n", g.inputTOML) log("# Effective Configuration, with defaults applied:\n%s\n", g.effectiveTOML) + if g.warning != nil { + warn("# Configuration warning:\n%s\n", g.warning) + } } // ConfigTOML implements chainlink.ConfigV2 @@ -506,7 +514,8 @@ func (g *generalConfig) Threshold() coreconfig.Threshold { return &thresholdConfig{s: g.secrets.Threshold} } -var ( - zeroURL = url.URL{} - zeroSha256Hash = models.Sha256Hash{} -) +func (g *generalConfig) Tracing() coreconfig.Tracing { + return &tracingConfig{s: g.c.Tracing} +} + +var zeroSha256Hash = models.Sha256Hash{} diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index 8e95e389ffc..46931e53e2b 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -5,13 +5,12 @@ package chainlink import ( _ "embed" "fmt" + "maps" "net/url" "strings" "testing" "time" - maps "golang.org/x/exp/maps" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/core/services/chainlink/config_p2p_test.go b/core/services/chainlink/config_p2p_test.go index d6adfe7051c..21ce8f17e48 100644 --- a/core/services/chainlink/config_p2p_test.go +++ b/core/services/chainlink/config_p2p_test.go @@ -4,9 +4,10 @@ import ( "testing" "time" - "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/libocr/commontypes" ) func TestP2PConfig(t *testing.T) { @@ -23,7 +24,7 @@ func TestP2PConfig(t *testing.T) { assert.True(t, p2p.TraceLogging()) v1 := p2p.V1() - assert.False(t, v1.Enabled()) + assert.True(t, v1.Enabled()) assert.Equal(t, "1.2.3.4", v1.AnnounceIP().String()) assert.Equal(t, uint16(1234), v1.AnnouncePort()) assert.Equal(t, time.Minute, v1.BootstrapCheckInterval()) @@ -38,7 +39,7 @@ func TestP2PConfig(t *testing.T) { assert.Equal(t, time.Minute, v1.PeerstoreWriteInterval()) v2 := p2p.V2() - assert.True(t, v2.Enabled()) + assert.False(t, v2.Enabled()) assert.Equal(t, []string{"a", "b", "c"}, v2.AnnounceAddresses()) assert.ElementsMatch( t, diff --git a/core/services/chainlink/config_telemetry_ingress.go b/core/services/chainlink/config_telemetry_ingress.go index 8557bf0b02a..5126833134e 100644 --- a/core/services/chainlink/config_telemetry_ingress.go +++ b/core/services/chainlink/config_telemetry_ingress.go @@ -14,6 +14,10 @@ type telemetryIngressConfig struct { c toml.TelemetryIngress } +type telemetryIngressEndpointConfig struct { + c toml.TelemetryIngressEndpoint +} + func (t *telemetryIngressConfig) Logging() bool { return *t.c.Logging } @@ -22,17 +26,6 @@ func (t *telemetryIngressConfig) UniConn() bool { return *t.c.UniConn } -func (t *telemetryIngressConfig) ServerPubKey() string { - return *t.c.ServerPubKey -} - -func (t *telemetryIngressConfig) URL() *url.URL { - if t.c.URL.IsZero() { - return nil - } - return t.c.URL.URL() -} - func (t *telemetryIngressConfig) BufferSize() uint { return uint(*t.c.BufferSize) } @@ -52,3 +45,42 @@ func (t *telemetryIngressConfig) SendTimeout() time.Duration { func (t *telemetryIngressConfig) UseBatchSend() bool { return *t.c.UseBatchSend } + +// Deprecated: Use TelemetryIngressEndpoint.ServerPubKey, this field will be removed in future versions +func (t *telemetryIngressConfig) ServerPubKey() string { + return *t.c.ServerPubKey +} + +// Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions +func (t *telemetryIngressConfig) URL() *url.URL { + return t.c.URL.URL() +} + +func (t *telemetryIngressConfig) Endpoints() []config.TelemetryIngressEndpoint { + var endpoints []config.TelemetryIngressEndpoint + for _, e := range t.c.Endpoints { + endpoints = append(endpoints, &telemetryIngressEndpointConfig{ + c: e, + }) + } + return endpoints +} + +func (t *telemetryIngressEndpointConfig) Network() string { + return *t.c.Network +} + +func (t *telemetryIngressEndpointConfig) ChainID() string { + return *t.c.ChainID +} + +func (t *telemetryIngressEndpointConfig) URL() *url.URL { + if t.c.URL.IsZero() { + return nil + } + return t.c.URL.URL() +} + +func (t *telemetryIngressEndpointConfig) ServerPubKey() string { + return *t.c.ServerPubKey +} diff --git a/core/services/chainlink/config_telemetry_ingress_test.go b/core/services/chainlink/config_telemetry_ingress_test.go index 5e4561440c5..c371b465a2b 100644 --- a/core/services/chainlink/config_telemetry_ingress_test.go +++ b/core/services/chainlink/config_telemetry_ingress_test.go @@ -18,11 +18,17 @@ func TestTelemetryIngressConfig(t *testing.T) { ticfg := cfg.TelemetryIngress() assert.True(t, ticfg.Logging()) assert.True(t, ticfg.UniConn()) - assert.Equal(t, "test-pub-key", ticfg.ServerPubKey()) - assert.Equal(t, "https://prom.test", ticfg.URL().String()) assert.Equal(t, uint(1234), ticfg.BufferSize()) assert.Equal(t, uint(4321), ticfg.MaxBatchSize()) assert.Equal(t, time.Minute, ticfg.SendInterval()) assert.Equal(t, 5*time.Second, ticfg.SendTimeout()) assert.True(t, ticfg.UseBatchSend()) + + tec := cfg.TelemetryIngress().Endpoints() + + assert.Equal(t, 1, len(tec)) + assert.Equal(t, "EVM", tec[0].Network()) + assert.Equal(t, "1", tec[0].ChainID()) + assert.Equal(t, "prom.test", tec[0].URL().String()) + assert.Equal(t, "test-pub-key", tec[0].ServerPubKey()) } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 480d06b5806..597dab6ba1c 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -10,13 +10,15 @@ import ( "github.com/kylelemons/godebug/diff" "github.com/shopspring/decimal" - ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" relayutils "github.com/smartcontractkit/chainlink-relay/pkg/utils" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" @@ -24,8 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" legacy "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -156,7 +156,7 @@ var ( {Name: ptr("secondary"), TendermintURL: relayutils.MustParseURL("http://bombay.cosmos.com")}, }}, }, - Solana: []*solana.SolanaConfig{ + Solana: []*solana.TOMLConfig{ { ChainID: ptr("mainnet"), Chain: solcfg.Chain{ @@ -176,7 +176,7 @@ var ( }, }, }, - Starknet: []*starknet.StarknetConfig{ + Starknet: []*stkcfg.TOMLConfig{ { ChainID: ptr("foobar"), Chain: stkcfg.Chain{ @@ -191,6 +191,7 @@ var ( ) func TestConfig_Marshal(t *testing.T) { + zeroSeconds := models.MustMakeDuration(time.Second * 0) second := models.MustMakeDuration(time.Second) minute := models.MustMakeDuration(time.Minute) hour := models.MustMakeDuration(time.Hour) @@ -222,6 +223,16 @@ func TestConfig_Marshal(t *testing.T) { InfiniteDepthQueries: ptr(false), DisableRateLimiting: ptr(false), }, + Tracing: toml.Tracing{ + Enabled: ptr(true), + CollectorTarget: ptr("localhost:4317"), + NodeID: ptr("clc-ocr-sol-devnet-node-1"), + Attributes: map[string]string{ + "test": "load", + "env": "dev", + }, + SamplingRatio: ptr(1.0), + }, }, } @@ -271,14 +282,21 @@ func TestConfig_Marshal(t *testing.T) { full.TelemetryIngress = toml.TelemetryIngress{ UniConn: ptr(true), Logging: ptr(true), - ServerPubKey: ptr("test-pub-key"), - URL: mustURL("https://prom.test"), BufferSize: ptr[uint16](1234), MaxBatchSize: ptr[uint16](4321), SendInterval: models.MustNewDuration(time.Minute), SendTimeout: models.MustNewDuration(5 * time.Second), UseBatchSend: ptr(true), + URL: ptr(models.URL{}), + ServerPubKey: ptr(""), + Endpoints: []toml.TelemetryIngressEndpoint{{ + Network: ptr("EVM"), + ChainID: ptr("1"), + ServerPubKey: ptr("test-pub-key"), + URL: mustURL("prom.test")}, + }, } + full.Log = toml.Log{ Level: ptr(toml.LogLevel(zapcore.DPanicLevel)), JSONConsole: ptr(true), @@ -371,7 +389,7 @@ func TestConfig_Marshal(t *testing.T) { PeerID: mustPeerID("12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw"), TraceLogging: ptr(true), V1: toml.P2PV1{ - Enabled: ptr(false), + Enabled: ptr(true), AnnounceIP: mustIP("1.2.3.4"), AnnouncePort: ptr[uint16](1234), BootstrapCheckInterval: models.MustNewDuration(time.Minute), @@ -384,7 +402,7 @@ func TestConfig_Marshal(t *testing.T) { PeerstoreWriteInterval: models.MustNewDuration(time.Minute), }, V2: toml.P2PV2{ - Enabled: ptr(true), + Enabled: ptr(false), AnnounceAddresses: &[]string{"a", "b", "c"}, DefaultBootstrappers: &[]ocrcommontypes.BootstrapperLocator{ {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"foo:42", "bar:10"}}, @@ -528,6 +546,7 @@ func TestConfig_Marshal(t *testing.T) { PollInterval: &minute, SelectionMode: &selectionMode, SyncThreshold: ptr[uint32](13), + LeaseDuration: &zeroSeconds, }, OCR: evmcfg.OCR{ ContractConfirmations: ptr[uint16](11), @@ -559,7 +578,7 @@ func TestConfig_Marshal(t *testing.T) { }, }}, } - full.Solana = []*solana.SolanaConfig{ + full.Solana = []*solana.TOMLConfig{ { ChainID: ptr("mainnet"), Enabled: ptr(false), @@ -587,7 +606,7 @@ func TestConfig_Marshal(t *testing.T) { }, }, } - full.Starknet = []*starknet.StarknetConfig{ + full.Starknet = []*stkcfg.TOMLConfig{ { ChainID: ptr("foobar"), Enabled: ptr(true), @@ -643,6 +662,16 @@ DevWebServer = false OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false + +[Tracing] +Enabled = true +CollectorTarget = 'localhost:4317' +NodeID = 'clc-ocr-sol-devnet-node-1' +SamplingRatio = 1.0 + +[Tracing.Attributes] +env = 'dev' +test = 'load' `}, {"AuditLogger", Config{Core: toml.Core{AuditLogger: full.AuditLogger}}, `[AuditLogger] Enabled = true @@ -683,14 +712,21 @@ LeaseRefreshInterval = '1s' {"TelemetryIngress", Config{Core: toml.Core{TelemetryIngress: full.TelemetryIngress}}, `[TelemetryIngress] UniConn = true Logging = true -ServerPubKey = 'test-pub-key' -URL = 'https://prom.test' BufferSize = 1234 MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true +URL = '' +ServerPubKey = '' + +[[TelemetryIngress.Endpoints]] +Network = 'EVM' +ChainID = '1' +URL = 'prom.test' +ServerPubKey = 'test-pub-key' `}, + {"Log", Config{Core: toml.Core{Log: full.Log}}, `[Log] Level = 'crit' JSONConsole = true @@ -784,7 +820,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -797,7 +833,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' @@ -926,6 +962,7 @@ PollFailureThreshold = 5 PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 11 @@ -1059,6 +1096,17 @@ func TestConfig_full(t *testing.T) { } } + // Except for TelemetryIngress.ServerPubKey as this will be removed in the future + // and its only use is to signal to NOPs that these fields are no longer allowed + if got.TelemetryIngress.ServerPubKey == nil { + got.TelemetryIngress.ServerPubKey = ptr("") + } + // Except for TelemetryIngress.URL as this will be removed in the future + // and its only use is to signal to NOPs that these fields are no longer allowed + if got.TelemetryIngress.URL == nil { + got.TelemetryIngress.URL = new(models.URL) + } + cfgtest.AssertFieldsNotNil(t, got) } @@ -1200,6 +1248,21 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { secrets = "# Secrets:\n" input = "# Input Configuration:\n" effective = "# Effective Configuration, with defaults applied:\n" + warning = "# Configuration warning:\n" + + deprecated = `2 errors: + - P2P.V1: is deprecated and will be removed in a future version + - P2P.V1: 10 errors: + - AnnounceIP: is deprecated and will be removed in a future version + - AnnouncePort: is deprecated and will be removed in a future version + - BootstrapCheckInterval: is deprecated and will be removed in a future version + - DefaultBootstrapPeers: is deprecated and will be removed in a future version + - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version + - DHTLookupInterval: is deprecated and will be removed in a future version + - ListenIP: is deprecated and will be removed in a future version + - ListenPort: is deprecated and will be removed in a future version + - NewStreamTimeout: is deprecated and will be removed in a future version + - PeerstoreWriteInterval: is deprecated and will be removed in a future version` ) tests := []struct { name string @@ -1209,10 +1272,11 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { wantConfig string wantEffective string wantSecrets string + wantWarning string }{ {name: "empty", wantEffective: emptyEffectiveTOML, wantSecrets: emptyEffectiveSecretsTOML}, {name: "full", inputSecrets: secretsFullTOML, inputConfig: fullTOML, - wantConfig: fullTOML, wantEffective: fullTOML, wantSecrets: secretsFullRedactedTOML}, + wantConfig: fullTOML, wantEffective: fullTOML, wantSecrets: secretsFullRedactedTOML, wantWarning: deprecated}, {name: "multi-chain", inputSecrets: secretsMultiTOML, inputConfig: multiChainTOML, wantConfig: multiChainTOML, wantEffective: multiChainEffectiveTOML, wantSecrets: secretsMultiRedactedTOML}, } @@ -1226,10 +1290,11 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { } c, err := opts.New() require.NoError(t, err) - c.LogConfiguration(lggr.Infof) + c.LogConfiguration(lggr.Infof, lggr.Warnf) inputLogs := observed.FilterMessageSnippet(secrets).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, secrets) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantSecrets, got) @@ -1237,6 +1302,7 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { inputLogs = observed.FilterMessageSnippet(input).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, input) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantConfig, got) @@ -1244,10 +1310,19 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { inputLogs = observed.FilterMessageSnippet(effective).All() if assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.InfoLevel, inputLogs[0].Level) got := strings.TrimPrefix(inputLogs[0].Message, effective) got = strings.TrimSuffix(got, "\n") assert.Equal(t, tt.wantEffective, got) } + + inputLogs = observed.FilterMessageSnippet(warning).All() + if tt.wantWarning != "" && assert.Len(t, inputLogs, 1) { + assert.Equal(t, zapcore.WarnLevel, inputLogs[0].Level) + got := strings.TrimPrefix(inputLogs[0].Message, warning) + got = strings.TrimSuffix(got, "\n") + assert.Equal(t, tt.wantWarning, got) + } }) } } @@ -1361,8 +1436,8 @@ func TestConfig_setDefaults(t *testing.T) { var c Config c.EVM = evmcfg.EVMConfigs{{ChainID: utils.NewBigI(99999133712345)}} c.Cosmos = cosmos.CosmosConfigs{{ChainID: ptr("unknown cosmos chain")}} - c.Solana = solana.SolanaConfigs{{ChainID: ptr("unknown solana chain")}} - c.Starknet = starknet.StarknetConfigs{{ChainID: ptr("unknown starknet chain")}} + c.Solana = solana.TOMLConfigs{{ChainID: ptr("unknown solana chain")}} + c.Starknet = stkcfg.TOMLConfigs{{ChainID: ptr("unknown starknet chain")}} c.setDefaults() if s, err := c.TOMLString(); assert.NoError(t, err) { t.Log(s, err) diff --git a/core/services/chainlink/config_tracing.go b/core/services/chainlink/config_tracing.go new file mode 100644 index 00000000000..390645974f1 --- /dev/null +++ b/core/services/chainlink/config_tracing.go @@ -0,0 +1,27 @@ +package chainlink + +import "github.com/smartcontractkit/chainlink/v2/core/config/toml" + +type tracingConfig struct { + s toml.Tracing +} + +func (t tracingConfig) Enabled() bool { + return *t.s.Enabled +} + +func (t tracingConfig) CollectorTarget() string { + return *t.s.CollectorTarget +} + +func (t tracingConfig) NodeID() string { + return *t.s.NodeID +} + +func (t tracingConfig) Attributes() map[string]string { + return t.s.Attributes +} + +func (t tracingConfig) SamplingRatio() float64 { + return *t.s.SamplingRatio +} diff --git a/core/services/chainlink/config_tracing_test.go b/core/services/chainlink/config_tracing_test.go new file mode 100644 index 00000000000..5968bc306a2 --- /dev/null +++ b/core/services/chainlink/config_tracing_test.go @@ -0,0 +1,42 @@ +package chainlink + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/config/toml" +) + +func TestTracing_Config(t *testing.T) { + // Test when all fields are non-nil + enabled := true + collectorTarget := "http://localhost:9000" + nodeID := "Node1" + samplingRatio := 0.5 + attributes := map[string]string{"key": "value"} + tracing := toml.Tracing{ + Enabled: &enabled, + CollectorTarget: &collectorTarget, + NodeID: &nodeID, + SamplingRatio: &samplingRatio, + Attributes: attributes, + } + tConfig := tracingConfig{s: tracing} + + assert.True(t, tConfig.Enabled()) + assert.Equal(t, "http://localhost:9000", tConfig.CollectorTarget()) + assert.Equal(t, "Node1", tConfig.NodeID()) + assert.Equal(t, 0.5, tConfig.SamplingRatio()) + assert.Equal(t, map[string]string{"key": "value"}, tConfig.Attributes()) + + // Test when all fields are nil + nilTracing := toml.Tracing{} + nilConfig := tracingConfig{s: nilTracing} + + assert.Panics(t, func() { nilConfig.Enabled() }) + assert.Panics(t, func() { nilConfig.CollectorTarget() }) + assert.Panics(t, func() { nilConfig.NodeID() }) + assert.Panics(t, func() { nilConfig.SamplingRatio() }) + assert.Nil(t, nilConfig.Attributes()) +} diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 416fbd33756..0bc51ea4310 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -1,16 +1,16 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( - cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" + chainlinkconfig "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" config "github.com/smartcontractkit/chainlink/v2/core/config" - mock "github.com/stretchr/testify/mock" + cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" - solana "github.com/smartcontractkit/chainlink/v2/core/chains/solana" + mock "github.com/stretchr/testify/mock" - starknet "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" + solana "github.com/smartcontractkit/chainlink-solana/pkg/solana" time "time" @@ -298,9 +298,9 @@ func (_m *GeneralConfig) Log() config.Log { return r0 } -// LogConfiguration provides a mock function with given fields: log -func (_m *GeneralConfig) LogConfiguration(log config.LogfFn) { - _m.Called(log) +// LogConfiguration provides a mock function with given fields: log, warn +func (_m *GeneralConfig) LogConfiguration(log config.LogfFn, warn config.LogfFn) { + _m.Called(log, warn) } // Mercury provides a mock function with given fields: @@ -484,15 +484,15 @@ func (_m *GeneralConfig) ShutdownGracePeriod() time.Duration { } // SolanaConfigs provides a mock function with given fields: -func (_m *GeneralConfig) SolanaConfigs() solana.SolanaConfigs { +func (_m *GeneralConfig) SolanaConfigs() solana.TOMLConfigs { ret := _m.Called() - var r0 solana.SolanaConfigs - if rf, ok := ret.Get(0).(func() solana.SolanaConfigs); ok { + var r0 solana.TOMLConfigs + if rf, ok := ret.Get(0).(func() solana.TOMLConfigs); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(solana.SolanaConfigs) + r0 = ret.Get(0).(solana.TOMLConfigs) } } @@ -528,15 +528,15 @@ func (_m *GeneralConfig) StarkNetEnabled() bool { } // StarknetConfigs provides a mock function with given fields: -func (_m *GeneralConfig) StarknetConfigs() starknet.StarknetConfigs { +func (_m *GeneralConfig) StarknetConfigs() chainlinkconfig.TOMLConfigs { ret := _m.Called() - var r0 starknet.StarknetConfigs - if rf, ok := ret.Get(0).(func() starknet.StarknetConfigs); ok { + var r0 chainlinkconfig.TOMLConfigs + if rf, ok := ret.Get(0).(func() chainlinkconfig.TOMLConfigs); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(starknet.StarknetConfigs) + r0 = ret.Get(0).(chainlinkconfig.TOMLConfigs) } } @@ -575,6 +575,22 @@ func (_m *GeneralConfig) Threshold() config.Threshold { return r0 } +// Tracing provides a mock function with given fields: +func (_m *GeneralConfig) Tracing() config.Tracing { + ret := _m.Called() + + var r0 config.Tracing + if rf, ok := ret.Get(0).(func() config.Tracing); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Tracing) + } + } + + return r0 +} + // Validate provides a mock function with given fields: func (_m *GeneralConfig) Validate() error { ret := _m.Called() @@ -619,13 +635,12 @@ func (_m *GeneralConfig) WebServer() config.WebServer { return r0 } -type mockConstructorTestingTNewGeneralConfig interface { +// NewGeneralConfig creates a new instance of GeneralConfig. 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 NewGeneralConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewGeneralConfig creates a new instance of GeneralConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewGeneralConfig(t mockConstructorTestingTNewGeneralConfig) *GeneralConfig { +}) *GeneralConfig { mock := &GeneralConfig{} mock.Mock.Test(t) diff --git a/core/services/chainlink/mocks/relayer_chain_interoperators.go b/core/services/chainlink/mocks/relayer_chain_interoperators.go index c0eb699a492..0a8758f6d4b 100644 --- a/core/services/chainlink/mocks/relayer_chain_interoperators.go +++ b/core/services/chainlink/mocks/relayer_chain_interoperators.go @@ -10,7 +10,7 @@ import ( cosmos "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" evm "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - + // Manually edited. mockery generates the wrong dependency. edited to use `loop` rather than `loop/internal` // seems to caused by incorrect alias resolution of the relayer dep internal "github.com/smartcontractkit/chainlink-relay/pkg/loop" diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 6513184d9ec..e039afbfc91 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -144,9 +144,9 @@ func InitCosmos(ctx context.Context, factory RelayerFactory, config CosmosFactor // InitSolana is a option for instantiating Solana relayers func InitSolana(ctx context.Context, factory RelayerFactory, config SolanaFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) error { - solRelayers, err2 := factory.NewSolana(config.Keystore, config.SolanaConfigs) - if err2 != nil { - return fmt.Errorf("failed to setup Solana relayer: %w", err2) + solRelayers, err := factory.NewSolana(config.Keystore, config.TOMLConfigs) + if err != nil { + return fmt.Errorf("failed to setup Solana relayer: %w", err) } for id, relayer := range solRelayers { @@ -161,9 +161,9 @@ func InitSolana(ctx context.Context, factory RelayerFactory, config SolanaFactor // InitStarknet is a option for instantiating Starknet relayers func InitStarknet(ctx context.Context, factory RelayerFactory, config StarkNetFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - starkRelayers, err2 := factory.NewStarkNet(config.Keystore, config.StarknetConfigs) - if err2 != nil { - return fmt.Errorf("failed to setup StarkNet relayer: %w", err2) + starkRelayers, err := factory.NewStarkNet(config.Keystore, config.TOMLConfigs) + if err != nil { + return fmt.Errorf("failed to setup StarkNet relayer: %w", err) } for id, relayer := range starkRelayers { diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 527dacd56d8..5b17e2e4232 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -15,10 +15,9 @@ import ( solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -79,8 +78,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: evmcfg.EVMNodes{&node2_1}, }) - c.Solana = solana.SolanaConfigs{ - &solana.SolanaConfig{ + c.Solana = solana.TOMLConfigs{ + &solana.TOMLConfig{ ChainID: &solanaChainID1, Enabled: ptr(true), Chain: solcfg.Chain{}, @@ -89,7 +88,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { URL: ((*relayutils.URL)(models.MustParseURL("http://localhost:8547").URL())), }}, }, - &solana.SolanaConfig{ + &solana.TOMLConfig{ ChainID: &solanaChainID2, Enabled: ptr(true), Chain: solcfg.Chain{}, @@ -100,8 +99,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, } - c.Starknet = starknet.StarknetConfigs{ - &starknet.StarknetConfig{ + c.Starknet = stkcfg.TOMLConfigs{ + &stkcfg.TOMLConfig{ ChainID: &starknetChainID1, Enabled: ptr(true), Chain: stkcfg.Chain{}, @@ -120,7 +119,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, }, }, - &starknet.StarknetConfig{ + &stkcfg.TOMLConfig{ ChainID: &starknetChainID2, Enabled: ptr(true), Chain: stkcfg.Chain{}, @@ -174,7 +173,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { factory := chainlink.RelayerFactory{ Logger: lggr, - LoopRegistry: plugins.NewLoopRegistry(lggr), + LoopRegistry: plugins.NewLoopRegistry(lggr, nil), GRPCOpts: loop.GRPCOpts{}, } @@ -227,8 +226,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitSolana(testctx, factory, chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - SolanaConfigs: cfg.SolanaConfigs()}), + Keystore: keyStore.Solana(), + TOMLConfigs: cfg.SolanaConfigs()}), }, expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, @@ -243,8 +242,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitStarknet(testctx, factory, chainlink.StarkNetFactoryConfig{ - Keystore: keyStore.StarkNet(), - StarknetConfigs: cfg.StarknetConfigs()}), + Keystore: keyStore.StarkNet(), + TOMLConfigs: cfg.StarknetConfigs()}), }, expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, @@ -277,8 +276,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { {name: "all chains", initFuncs: []chainlink.CoreRelayerChainInitFunc{chainlink.InitSolana(testctx, factory, chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - SolanaConfigs: cfg.SolanaConfigs()}), + Keystore: keyStore.Solana(), + TOMLConfigs: cfg.SolanaConfigs()}), chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: evm.ChainOpts{ AppConfig: cfg, @@ -289,8 +288,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { CSAETHKeystore: keyStore, }), chainlink.InitStarknet(testctx, factory, chainlink.StarkNetFactoryConfig{ - Keystore: keyStore.StarkNet(), - StarknetConfigs: cfg.StarknetConfigs()}), + Keystore: keyStore.StarkNet(), + TOMLConfigs: cfg.StarknetConfigs()}), chainlink.InitCosmos(testctx, factory, chainlink.CosmosFactoryConfig{ Keystore: keyStore.Cosmos(), CosmosConfigs: cfg.CosmosConfigs(), @@ -334,25 +333,30 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - cr, err := chainlink.NewCoreRelayerChainInteroperators(tt.initFuncs...) - require.NoError(t, err) - - expectedChainCnt := tt.expectedEVMChainCnt + tt.expectedCosmosChainCnt + tt.expectedSolanaChainCnt + tt.expectedStarknetChainCnt - allChainsStats, cnt, err := cr.ChainStatuses(testctx, 0, 0) - assert.NoError(t, err) - assert.Len(t, allChainsStats, expectedChainCnt) - assert.Equal(t, cnt, len(allChainsStats)) - assert.Len(t, cr.Slice(), expectedChainCnt) - - // should be one relayer per chain and one service per relayer - assert.Len(t, cr.Slice(), expectedChainCnt) - assert.Len(t, cr.Services(), expectedChainCnt) - - expectedNodeCnt := tt.expectedEVMNodeCnt + tt.expectedCosmosNodeCnt + tt.expectedSolanaNodeCnt + tt.expectedStarknetNodeCnt - allNodeStats, cnt, err := cr.NodeStatuses(testctx, 0, 0) - assert.NoError(t, err) - assert.Len(t, allNodeStats, expectedNodeCnt) - assert.Equal(t, cnt, len(allNodeStats)) + + var cr *chainlink.CoreRelayerChainInteroperators + { + var err error + cr, err = chainlink.NewCoreRelayerChainInteroperators(tt.initFuncs...) + require.NoError(t, err) + + expectedChainCnt := tt.expectedEVMChainCnt + tt.expectedCosmosChainCnt + tt.expectedSolanaChainCnt + tt.expectedStarknetChainCnt + allChainsStats, cnt, err := cr.ChainStatuses(testctx, 0, 0) + assert.NoError(t, err) + assert.Len(t, allChainsStats, expectedChainCnt) + assert.Equal(t, cnt, len(allChainsStats)) + assert.Len(t, cr.Slice(), expectedChainCnt) + + // should be one relayer per chain and one service per relayer + assert.Len(t, cr.Slice(), expectedChainCnt) + assert.Len(t, cr.Services(), expectedChainCnt) + + expectedNodeCnt := tt.expectedEVMNodeCnt + tt.expectedCosmosNodeCnt + tt.expectedSolanaNodeCnt + tt.expectedStarknetNodeCnt + allNodeStats, cnt, err := cr.NodeStatuses(testctx, 0, 0) + assert.NoError(t, err) + assert.Len(t, allNodeStats, expectedNodeCnt) + assert.Equal(t, cnt, len(allNodeStats)) + } gotRelayerNetworks := make(map[relay.Network]struct{}) for relayNetwork := range relay.SupportedRelays { diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index c0541f4384d..31251069df5 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -11,13 +11,13 @@ import ( pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" "github.com/smartcontractkit/chainlink-relay/pkg/loop" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" pkgsolana "github.com/smartcontractkit/chainlink-solana/pkg/solana" pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink" - + starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" + "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -56,7 +56,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m } legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) for _, ext := range evmRelayExtenders.Slice() { - relayID := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(ext.Chain().ID().String())} + relayID := relay.ID{Network: relay.EVM, ChainID: ext.Chain().ID().String()} chain, err2 := legacyChains.Get(relayID.ChainID) if err2 != nil { return nil, err2 @@ -68,7 +68,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m CSAETHKeystore: config.CSAETHKeystore, EventBroadcaster: ccOpts.EventBroadcaster, } - relayer, err2 := evmrelay.NewRelayer(ccOpts.Logger, chain, relayerOpts) + relayer, err2 := evmrelay.NewRelayer(ccOpts.Logger.Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { err = errors.Join(err, err2) continue @@ -83,10 +83,10 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m type SolanaFactoryConfig struct { Keystore keystore.Solana - solana.SolanaConfigs + solana.TOMLConfigs } -func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaConfigs) (map[relay.ID]loop.Relayer, error) { +func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConfigs) (map[relay.ID]loop.Relayer, error) { solanaRelayers := make(map[relay.ID]loop.Relayer) var ( solLggr = r.Logger.Named("Solana") @@ -97,12 +97,12 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo // create one relayer per chain id for _, chainCfg := range chainCfgs { - relayId := relay.ID{Network: relay.Solana, ChainID: relay.ChainID(*chainCfg.ChainID)} - _, alreadyExists := unique[relayId.Name()] + relayID := relay.ID{Network: relay.Solana, ChainID: *chainCfg.ChainID} + _, alreadyExists := unique[relayID.Name()] if alreadyExists { - return nil, fmt.Errorf("duplicate chain definitions for %s", relayId.Name()) + return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name()) } - unique[relayId.Name()] = struct{}{} + unique[relayID.Name()] = struct{}{} // skip disabled chains from further processing if !chainCfg.IsEnabled() { @@ -110,11 +110,13 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo continue } + lggr := solLggr.Named(relayID.ChainID) + if cmdName := env.SolanaPluginCmd.Get(); cmdName != "" { // setup the solana relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { - Solana solana.SolanaConfig + Solana solana.TOMLConfig }{Solana: *chainCfg}) if err != nil { @@ -122,19 +124,19 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo } solCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ - ID: relayId.Name(), + ID: relayID.Name(), Cmd: cmdName, }) if err != nil { return nil, fmt.Errorf("failed to create Solana LOOP command: %w", err) } - solanaRelayers[relayId] = loop.NewRelayerService(solLggr, r.GRPCOpts, solCmdFn, string(cfgTOML), signer) + solanaRelayers[relayID] = loop.NewRelayerService(lggr, r.GRPCOpts, solCmdFn, string(cfgTOML), signer) } else { // fallback to embedded chain opts := solana.ChainOpts{ - Logger: solLggr, + Logger: lggr, KeyStore: signer, } @@ -142,7 +144,7 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo if err != nil { return nil, err } - solanaRelayers[relayId] = relay.NewRelayerServerAdapter(pkgsolana.NewRelayer(solLggr, chain), chain) + solanaRelayers[relayID] = relay.NewServerAdapter(pkgsolana.NewRelayer(lggr, chain), chain) } } return solanaRelayers, nil @@ -150,12 +152,12 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo type StarkNetFactoryConfig struct { Keystore keystore.StarkNet - starknet.StarknetConfigs + config.TOMLConfigs } // TODO BCF-2606 consider consolidating the driving logic with that of NewSolana above via generics // perhaps when we implement a Cosmos LOOP -func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.StarknetConfigs) (map[relay.ID]loop.Relayer, error) { +func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOMLConfigs) (map[relay.ID]loop.Relayer, error) { starknetRelayers := make(map[relay.ID]loop.Relayer) var ( @@ -166,12 +168,12 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St unique := make(map[string]struct{}) // create one relayer per chain id for _, chainCfg := range chainCfgs { - relayId := relay.ID{Network: relay.StarkNet, ChainID: relay.ChainID(*chainCfg.ChainID)} - _, alreadyExists := unique[relayId.Name()] + relayID := relay.ID{Network: relay.StarkNet, ChainID: *chainCfg.ChainID} + _, alreadyExists := unique[relayID.Name()] if alreadyExists { - return nil, fmt.Errorf("duplicate chain definitions for %s", relayId.Name()) + return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name()) } - unique[relayId.Name()] = struct{}{} + unique[relayID.Name()] = struct{}{} // skip disabled chains from further processing if !chainCfg.IsEnabled() { @@ -179,17 +181,19 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St continue } + lggr := starkLggr.Named(relayID.ChainID) + if cmdName := env.StarknetPluginCmd.Get(); cmdName != "" { // setup the starknet relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { - Starknet starknet.StarknetConfig + Starknet config.TOMLConfig }{Starknet: *chainCfg}) if err != nil { return nil, fmt.Errorf("failed to marshal StarkNet configs: %w", err) } starknetCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ - ID: relayId.Name(), + ID: relayID.Name(), Cmd: cmdName, }) if err != nil { @@ -197,20 +201,20 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St } // the starknet relayer service has a delicate keystore dependency. the value that is passed to NewRelayerService must // be compatible with instantiating a starknet transaction manager KeystoreAdapter within the LOOPp executable. - starknetRelayers[relayId] = loop.NewRelayerService(starkLggr, r.GRPCOpts, starknetCmdFn, string(cfgTOML), loopKs) + starknetRelayers[relayID] = loop.NewRelayerService(lggr, r.GRPCOpts, starknetCmdFn, string(cfgTOML), loopKs) } else { // fallback to embedded chain - opts := starknet.ChainOpts{ - Logger: starkLggr, + opts := starkchain.ChainOpts{ + Logger: lggr, KeyStore: loopKs, } - chain, err := starknet.NewChain(chainCfg, opts) + chain, err := starkchain.NewChain(chainCfg, opts) if err != nil { return nil, err } - starknetRelayers[relayId] = relay.NewRelayerServerAdapter(pkgstarknet.NewRelayer(starkLggr, chain), chain) + starknetRelayers[relayID] = relay.NewServerAdapter(pkgstarknet.NewRelayer(lggr, chain), chain) } } return starknetRelayers, nil @@ -257,17 +261,19 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf relayers := make(map[relay.ID]cosmos.LoopRelayerChainer) var ( - lggr = r.Logger.Named("Cosmos") - loopKs = &keystore.CosmosLoopKeystore{Cosmos: config.Keystore} + cosmosLggr = r.Logger.Named("Cosmos") + loopKs = &keystore.CosmosLoopKeystore{Cosmos: config.Keystore} ) // create one relayer per chain id for _, chainCfg := range config.CosmosConfigs { - relayId := relay.ID{Network: relay.Cosmos, ChainID: relay.ChainID(*chainCfg.ChainID)} + relayID := relay.ID{Network: relay.Cosmos, ChainID: *chainCfg.ChainID} + + lggr := cosmosLggr.Named(relayID.ChainID) opts := cosmos.ChainOpts{ QueryConfig: config.QConfig, - Logger: lggr.Named(relayId.ChainID), + Logger: lggr, DB: config.DB, KeyStore: loopKs, EventBroadcaster: config.EventBroadcaster, @@ -275,10 +281,10 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf chain, err := cosmos.NewChain(chainCfg, opts) if err != nil { - return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayId, err) + return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayID, err) } - relayers[relayId] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, chain), chain) + relayers[relayID] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, chain), chain) } return relayers, nil diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 45e92a147d3..48d432138a8 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -35,13 +35,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -206,3 +206,9 @@ DevWebServer = false OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false + +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 92d0b553d6e..1534a411dc1 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -35,13 +35,19 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = true -ServerPubKey = 'test-pub-key' -URL = 'https://prom.test' BufferSize = 1234 MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true +URL = '' +ServerPubKey = '' + +[[TelemetryIngress.Endpoints]] +Network = 'EVM' +ChainID = '1' +URL = 'prom.test' +ServerPubKey = 'test-pub-key' [AuditLogger] Enabled = true @@ -142,7 +148,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -155,7 +161,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' @@ -207,6 +213,16 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = true +CollectorTarget = 'localhost:4317' +NodeID = 'clc-ocr-sol-devnet-node-1' +SamplingRatio = 1.0 + +[Tracing.Attributes] +env = 'dev' +test = 'load' + [[EVM]] ChainID = '1' Enabled = false @@ -290,6 +306,7 @@ PollFailureThreshold = 5 PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 11 diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 665de9be8cb..1dcbfe3a830 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -35,13 +35,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = true @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -207,6 +207,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -271,6 +277,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 @@ -355,6 +362,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 @@ -433,6 +441,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/core/services/chainlink/types.go b/core/services/chainlink/types.go index a286dc3c234..1233a179617 100644 --- a/core/services/chainlink/types.go +++ b/core/services/chainlink/types.go @@ -1,10 +1,11 @@ package chainlink import ( + "github.com/smartcontractkit/chainlink-solana/pkg/solana" + stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" "github.com/smartcontractkit/chainlink/v2/core/config" ) @@ -14,8 +15,8 @@ type GeneralConfig interface { config.AppConfig toml.HasEVMConfigs CosmosConfigs() cosmos.CosmosConfigs - SolanaConfigs() solana.SolanaConfigs - StarknetConfigs() starknet.StarknetConfigs + SolanaConfigs() solana.TOMLConfigs + StarknetConfigs() stkcfg.TOMLConfigs // ConfigTOML returns both the user provided and effective configuration as TOML. ConfigTOML() (user, effective string) } diff --git a/core/services/checkable.go b/core/services/checkable.go deleted file mode 100644 index a702f9f979d..00000000000 --- a/core/services/checkable.go +++ /dev/null @@ -1,15 +0,0 @@ -package services - -// Checkable should be implemented by any type requiring health checks. -// From the k8s docs: -// > ready means it’s initialized and healthy means that it can accept traffic in kubernetes -// See: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ -type Checkable interface { - // Ready should return nil if ready, or an error message otherwise. - Ready() error - // HealthReport returns a full health report of the callee including it's dependencies. - // key is the dep name, value is nil if healthy, or error message otherwise. - HealthReport() map[string]error - // Name returns the fully qualified name of the component. Usually the logger name. - Name() string -} diff --git a/core/services/cron/delegate.go b/core/services/cron/delegate.go index a411a120128..c227fd60d00 100644 --- a/core/services/cron/delegate.go +++ b/core/services/cron/delegate.go @@ -33,7 +33,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the scheduler to be used for running cron jobs -func (d *Delegate) ServicesForSpec(spec job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { if spec.CronSpec == nil { return nil, errors.Errorf("services.Delegate expects a *jobSpec.CronSpec to be present, got %v", spec) } diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index 39564b8c8bd..75cebb7a74a 100644 --- a/core/services/directrequest/delegate.go +++ b/core/services/directrequest/delegate.go @@ -68,7 +68,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the log listener service for a direct request job -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if jb.DirectRequestSpec == nil { return nil, errors.Errorf("DirectRequest: directrequest.Delegate expects a *job.DirectRequestSpec to be present, got %v", jb) } @@ -83,7 +83,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC return nil, errors.Wrapf(err, "DirectRequest: failed to create an operator wrapper for address: %v", concreteSpec.ContractAddress.Address().String()) } - svcLogger := d.logger. + svcLogger := d.logger.Named(jb.ExternalJobID.String()). With( "contract", concreteSpec.ContractAddress.Address().String(), "jobName", jb.PipelineSpec.JobName, @@ -92,7 +92,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC ) logListener := &listener{ - logger: svcLogger.Named("DirectRequest"), + logger: svcLogger.Named("Listener"), config: chain.Config().EVM(), logBroadcaster: chain.LogBroadcaster(), oracle: oracle, diff --git a/core/services/feeds/mocks/connections_manager.go b/core/services/feeds/mocks/connections_manager.go index 5289b7996c8..e72c98a987a 100644 --- a/core/services/feeds/mocks/connections_manager.go +++ b/core/services/feeds/mocks/connections_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -78,13 +78,12 @@ func (_m *ConnectionsManager) IsConnected(id int64) bool { return r0 } -type mockConstructorTestingTNewConnectionsManager interface { +// NewConnectionsManager creates a new instance of ConnectionsManager. 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 NewConnectionsManager(t interface { mock.TestingT Cleanup(func()) -} - -// NewConnectionsManager creates a new instance of ConnectionsManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConnectionsManager(t mockConstructorTestingTNewConnectionsManager) *ConnectionsManager { +}) *ConnectionsManager { mock := &ConnectionsManager{} mock.Mock.Test(t) diff --git a/core/services/feeds/mocks/feeds_manager_client.go b/core/services/feeds/mocks/feeds_manager_client.go index 55d1b93f35f..9d0037ceabc 100644 --- a/core/services/feeds/mocks/feeds_manager_client.go +++ b/core/services/feeds/mocks/feeds_manager_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -144,13 +144,12 @@ func (_m *FeedsManagerClient) UpdateNode(ctx context.Context, in *proto.UpdateNo return r0, r1 } -type mockConstructorTestingTNewFeedsManagerClient interface { +// NewFeedsManagerClient creates a new instance of FeedsManagerClient. 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 NewFeedsManagerClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewFeedsManagerClient creates a new instance of FeedsManagerClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFeedsManagerClient(t mockConstructorTestingTNewFeedsManagerClient) *FeedsManagerClient { +}) *FeedsManagerClient { mock := &FeedsManagerClient{} mock.Mock.Test(t) diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index 67e33bdc1e6..09326ada518 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -2041,13 +2041,12 @@ func (_c *ORM_UpsertJobProposal_Call) RunAndReturn(run func(*feeds.JobProposal, return _c } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index 3721966317b..1681918bb74 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -633,13 +633,12 @@ func (_m *Service) UpdateSpecDefinition(ctx context.Context, id int64, spec stri return r0 } -type mockConstructorTestingTNewService interface { +// NewService creates a new instance of Service. 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 NewService(t interface { mock.TestingT Cleanup(func()) -} - -// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewService(t mockConstructorTestingTNewService) *Service { +}) *Service { mock := &Service{} mock.Mock.Test(t) diff --git a/core/services/feeds/models.go b/core/services/feeds/models.go index 8e30ca74b25..a5c8648fdd9 100644 --- a/core/services/feeds/models.go +++ b/core/services/feeds/models.go @@ -258,10 +258,12 @@ type JobProposalCounts struct { // toMetrics transforms JobProposalCounts into a map with float64 values for setting metrics // in prometheus. func (jpc *JobProposalCounts) toMetrics() map[JobProposalStatus]float64 { - metrics := make(map[JobProposalStatus]float64, 4) + metrics := make(map[JobProposalStatus]float64, 6) metrics[JobProposalStatusPending] = float64(jpc.Pending) metrics[JobProposalStatusApproved] = float64(jpc.Approved) metrics[JobProposalStatusCancelled] = float64(jpc.Cancelled) metrics[JobProposalStatusRejected] = float64(jpc.Rejected) + metrics[JobProposalStatusRevoked] = float64(jpc.Revoked) + metrics[JobProposalStatusDeleted] = float64(jpc.Deleted) return metrics } diff --git a/core/services/feeds/models_test.go b/core/services/feeds/models_test.go index 67d669b85f4..8a26d77e56a 100644 --- a/core/services/feeds/models_test.go +++ b/core/services/feeds/models_test.go @@ -376,3 +376,28 @@ func Test_JobProposal_CanEditDefinition(t *testing.T) { }) } } + +// Test_toMetrics tests the toMetrics method +func Test_toMetrics(t *testing.T) { + t.Parallel() + + jpCounts := JobProposalCounts{ + Cancelled: 0, + Pending: 1, + Approved: 2, + Rejected: 3, + Deleted: 4, + Revoked: 5, + } + + metrics := jpCounts.toMetrics() + + assert.Equal(t, metrics, map[JobProposalStatus]float64{ + JobProposalStatusCancelled: 0, + JobProposalStatusPending: 1, + JobProposalStatusApproved: 2, + JobProposalStatusRejected: 3, + JobProposalStatusDeleted: 4, + JobProposalStatusRevoked: 5, + }) +} diff --git a/core/services/feeds/orm.go b/core/services/feeds/orm.go index b0b0bb38b55..30b6ad632a6 100644 --- a/core/services/feeds/orm.go +++ b/core/services/feeds/orm.go @@ -561,23 +561,39 @@ SELECT exists ( return exists, errors.Wrap(err, "JobProposalSpecVersionExists failed") } -// DeleteProposal performs a soft delete of the job proposal by setting the status to deleted and -// update the status to deleted +// DeleteProposal performs a soft delete of the job proposal by setting the status to deleted func (o *orm) DeleteProposal(id int64, qopts ...pg.QOpt) error { + // Get the latest spec for the proposal. stmt := ` + SELECT id, definition, version, status, job_proposal_id, status_updated_at, created_at, updated_at +FROM job_proposal_specs +WHERE (job_proposal_id, version) IN +( + SELECT job_proposal_id, MAX(version) + FROM job_proposal_specs + GROUP BY job_proposal_id +) +AND job_proposal_id = $1 +` + + var spec JobProposalSpec + err := o.q.WithOpts(qopts...).Get(&spec, stmt, id) + if err != nil { + return err + } + + // Set pending update to true only if the latest proposal is approved so that any running jobs + // are reminded to be cancelled. + pendingUpdate := spec.Status == SpecStatusApproved + stmt = ` UPDATE job_proposals SET status = $1, - pending_update = ( - CASE - WHEN status = 'approved' THEN true - ELSE false - END - ), + pending_update = $3, updated_at = NOW() WHERE id = $2; ` - result, err := o.q.WithOpts(qopts...).Exec(stmt, JobProposalStatusDeleted, id) + result, err := o.q.WithOpts(qopts...).Exec(stmt, JobProposalStatusDeleted, id, pendingUpdate) if err != nil { return err } diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index f2dacc4f02f..fab9d39a265 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -570,70 +570,190 @@ func Test_ORM_ListJobProposals(t *testing.T) { func Test_ORM_CountJobProposalsByStatus(t *testing.T) { t.Parallel() - var ( - orm = setupORM(t) - fmID = createFeedsManager(t, orm) + testCases := []struct { + name string + before func(orm *TestORM) *feeds.JobProposalCounts + wantApproved, wantRejected, wantDeleted, wantRevoked, wantPending, wantCancelled int64 + }{ + { + name: "correctly counts when there are no job proposals", + before: func(orm *TestORM) *feeds.JobProposalCounts { + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) - // Set initial values for job proposal counts - wantApproved, wantRejected, wantDeleted, wantRevoked int64 - wantPending, wantCancelled = int64(1), int64(1) - ) + return counts + }, + }, + { + name: "correctly counts a pending and cancelled job proposal by status", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) + createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - // Create a pending job proposal. - _, err := orm.CreateJobProposal(&feeds.JobProposal{ - RemoteUUID: uuid.New(), - Status: feeds.JobProposalStatusPending, - FeedsManagerID: fmID, - }) - require.NoError(t, err) + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) - // Create a cancelled job proposal. - cancelledUUID := uuid.New() - _, err = orm.CreateJobProposal(&feeds.JobProposal{ - RemoteUUID: cancelledUUID, - Status: feeds.JobProposalStatusCancelled, - FeedsManagerID: fmID, - }) - require.NoError(t, err) + return counts + }, + wantPending: 1, + wantCancelled: 1, + }, + { + // Verify that the counts are correct even if the proposal status is not pending. A + // spec is considered pending if its status is pending OR pending_update is TRUE + name: "correctly counts the pending specs when pending_update is true but the status itself is not pending", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) - // Get the initial count and assert against expected values. - counts, err := orm.CountJobProposalsByStatus() - require.NoError(t, err) + // Create a pending job proposal. + jUUID := uuid.New() + jpID, err := orm.CreateJobProposal(&feeds.JobProposal{ + RemoteUUID: jUUID, + Status: feeds.JobProposalStatusPending, + FeedsManagerID: fmID, + }) + require.NoError(t, err) - assert.Equal(t, wantPending, counts.Pending) - assert.Equal(t, wantApproved, counts.Approved) - assert.Equal(t, wantRejected, counts.Rejected) - assert.Equal(t, wantCancelled, counts.Cancelled) - assert.Equal(t, wantDeleted, counts.Deleted) - assert.Equal(t, wantRevoked, counts.Revoked) + // Upsert the proposal and change its status to rejected + _, err = orm.UpsertJobProposal(&feeds.JobProposal{ + RemoteUUID: jUUID, + Status: feeds.JobProposalStatusRejected, + FeedsManagerID: fmID, + }) + require.NoError(t, err) - // Upsert the cancelled job proposal to rejected - // which changes pending_update to TRUE, but leaves status as - // cancelled. - id, err := orm.UpsertJobProposal(&feeds.JobProposal{ - RemoteUUID: cancelledUUID, - Status: feeds.JobProposalStatusRejected, - FeedsManagerID: fmID, - }) - require.NoError(t, err) + // Assert that the upserted job proposal is now pending update. + jp, err := orm.GetJobProposal(jpID) + require.NoError(t, err) + assert.Equal(t, true, jp.PendingUpdate) - // Assert that the upserted job proposal is now pending update. - jp, err := orm.GetJobProposal(id) - require.NoError(t, err) - assert.Equal(t, true, jp.PendingUpdate) + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) - // Get final counts of job proposals and make assertions. - counts, err = orm.CountJobProposalsByStatus() - require.NoError(t, err) + return counts + }, + wantPending: 1, + }, + { + name: "correctly counts when approving a job proposal", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) + + // Create a pending job proposal. + jUUID := uuid.New() + jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + + // Create a spec for the pending job proposal + specID := createJobSpec(t, orm, int64(jpID)) + + // Defer the FK requirement of an existing job for a job proposal to be approved + require.NoError(t, utils.JustError(orm.db.Exec( + `SET CONSTRAINTS job_proposals_job_id_fkey DEFERRED`, + ))) + + // Approve the pending job proposal. + err := orm.ApproveSpec(specID, jUUID) + require.NoError(t, err) + + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) + + return counts + }, + wantApproved: 1, + }, + { + name: "correctly counts when revoking a job proposal", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) + jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + specID := createJobSpec(t, orm, jpID) + + // Revoke the pending job proposal. + err := orm.RevokeSpec(specID) + require.NoError(t, err) + + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) + + return counts + }, + wantRevoked: 1, + }, + { + name: "correctly counts when deleting a job proposal", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) + jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + createJobSpec(t, orm, jpID) + + // Delete the pending job proposal. + err := orm.DeleteProposal(jpID) + require.NoError(t, err) + + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) + + return counts + }, + wantDeleted: 1, + }, + { + name: "correctly counts when deleting a job proposal with an approved spec", + before: func(orm *TestORM) *feeds.JobProposalCounts { + fmID := createFeedsManager(t, orm) + + // Create a pending job proposal. + jUUID := uuid.New() + jpID, err := orm.CreateJobProposal(&feeds.JobProposal{ + RemoteUUID: jUUID, + Status: feeds.JobProposalStatusPending, + FeedsManagerID: fmID, + PendingUpdate: true, + }) + require.NoError(t, err) + + // Create a spec for the pending job proposal + specID := createJobSpec(t, orm, jpID) - wantPending = 2 // One pending + one pending update - wantCancelled = 0 - assert.Equal(t, wantPending, counts.Pending) - assert.Equal(t, wantApproved, counts.Approved) - assert.Equal(t, wantRejected, counts.Rejected) - assert.Equal(t, wantCancelled, counts.Cancelled) - assert.Equal(t, wantDeleted, counts.Deleted) - assert.Equal(t, wantRevoked, counts.Revoked) + // Defer the FK requirement of an existing job for a job proposal to be approved + require.NoError(t, utils.JustError(orm.db.Exec( + `SET CONSTRAINTS job_proposals_job_id_fkey DEFERRED`, + ))) + + err = orm.ApproveSpec(specID, jUUID) + require.NoError(t, err) + + // Delete the pending job proposal. + err = orm.DeleteProposal(jpID) + require.NoError(t, err) + + counts, err := orm.CountJobProposalsByStatus() + require.NoError(t, err) + + return counts + }, + wantPending: 1, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + orm := setupORM(t) + + counts := tc.before(orm) + + assert.Equal(t, tc.wantPending, counts.Pending) + assert.Equal(t, tc.wantApproved, counts.Approved) + assert.Equal(t, tc.wantRejected, counts.Rejected) + assert.Equal(t, tc.wantCancelled, counts.Cancelled) + assert.Equal(t, tc.wantDeleted, counts.Deleted) + assert.Equal(t, tc.wantRevoked, counts.Revoked) + }) + } } func Test_ORM_ListJobProposalByManagersIDs(t *testing.T) { @@ -936,6 +1056,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + createJobSpec(t, orm, int64(jpID)) return jpID }, @@ -943,7 +1064,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { wantProposalStatus: feeds.JobProposalStatusDeleted, }, { - name: "approved proposal", + name: "approved proposal with approved spec", before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) @@ -964,11 +1085,53 @@ func Test_ORM_DeleteProposal(t *testing.T) { wantProposalPendingUpdate: true, wantProposalStatus: feeds.JobProposalStatusDeleted, }, + { + name: "approved proposal with pending spec", + before: func(orm *TestORM) int64 { + fmID := createFeedsManager(t, orm) + jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) + specID := createJobSpec(t, orm, int64(jpID)) + + externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} + + // Defer the FK requirement of an existing job for a job proposal. + require.NoError(t, utils.JustError(orm.db.Exec( + `SET CONSTRAINTS job_proposals_job_id_fkey DEFERRED`, + ))) + + err := orm.ApproveSpec(specID, externalJobID.UUID) + require.NoError(t, err) + + jp, err := orm.GetJobProposal(jpID) + require.NoError(t, err) + + // Update the proposal to pending and create a new pending spec + _, err = orm.UpsertJobProposal(&feeds.JobProposal{ + RemoteUUID: jp.RemoteUUID, + Status: feeds.JobProposalStatusPending, + FeedsManagerID: fmID, + }) + require.NoError(t, err) + + _, err = orm.CreateSpec(feeds.JobProposalSpec{ + Definition: "spec data", + Version: 2, + Status: feeds.SpecStatusPending, + JobProposalID: jpID, + }) + require.NoError(t, err) + + return jpID + }, + wantProposalPendingUpdate: false, + wantProposalStatus: feeds.JobProposalStatusDeleted, + }, { name: "cancelled proposal", before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) + createJobSpec(t, orm, int64(jpID)) return jpID }, @@ -980,6 +1143,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) + createJobSpec(t, orm, int64(jpID)) return jpID }, @@ -987,7 +1151,17 @@ func Test_ORM_DeleteProposal(t *testing.T) { wantProposalStatus: feeds.JobProposalStatusDeleted, }, { - name: "not found", + name: "not found spec", + before: func(orm *TestORM) int64 { + fmID := createFeedsManager(t, orm) + jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) + + return jpID + }, + wantErr: "sql: no rows in result set", + }, + { + name: "not found proposal", before: func(orm *TestORM) int64 { return 0 }, @@ -1030,6 +1204,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { wantProposalStatus feeds.JobProposalStatus wantSpecStatus feeds.SpecStatus wantErr string + wantPendingUpdate bool }{ { name: "pending proposal", @@ -1042,6 +1217,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { }, wantProposalStatus: feeds.JobProposalStatusRevoked, wantSpecStatus: feeds.SpecStatusRevoked, + wantPendingUpdate: false, }, { name: "approved proposal", @@ -1133,6 +1309,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { assert.Equal(t, jpID, actualJP.ID) assert.Equal(t, tc.wantProposalStatus, actualJP.Status) + assert.Equal(t, tc.wantPendingUpdate, actualJP.PendingUpdate) } }) } diff --git a/core/services/feeds/proto/feeds_manager.pb.go b/core/services/feeds/proto/feeds_manager.pb.go index 77ab4289e42..880cb8ed1a4 100644 --- a/core/services/feeds/proto/feeds_manager.pb.go +++ b/core/services/feeds/proto/feeds_manager.pb.go @@ -7,10 +7,11 @@ package proto import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/core/services/feeds/rpc_handlers_test.go b/core/services/feeds/rpc_handlers_test.go index 26b21aeb65a..1648c05954d 100644 --- a/core/services/feeds/rpc_handlers_test.go +++ b/core/services/feeds/rpc_handlers_test.go @@ -1,6 +1,7 @@ package feeds_test import ( + "fmt" "testing" "github.com/google/uuid" @@ -34,10 +35,11 @@ func setupTestHandlers(t *testing.T) *TestRPCHandlers { func Test_RPCHandlers_ProposeJob(t *testing.T) { var ( - ctx = testutils.Context(t) - jobID = uuid.New() - spec = FluxMonitorTestSpec - version = int64(1) + ctx = testutils.Context(t) + jobID = uuid.New() + nameAndExternalJobID = uuid.New() + spec = fmt.Sprintf(FluxMonitorTestSpecTemplate, nameAndExternalJobID, nameAndExternalJobID) + version = int64(1) ) h := setupTestHandlers(t) diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 890cb586910..4c3647fde49 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -1025,7 +1025,7 @@ func (s *service) observeJobProposalCounts() error { // Set the prometheus gauge metrics. for _, status := range []JobProposalStatus{JobProposalStatusPending, JobProposalStatusApproved, - JobProposalStatusCancelled, JobProposalStatusRejected} { + JobProposalStatusCancelled, JobProposalStatusRejected, JobProposalStatusDeleted, JobProposalStatusRevoked} { status := status diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 85f14e407f8..744c5d14702 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -27,8 +27,8 @@ import ( jobmocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -45,12 +45,12 @@ import ( "gopkg.in/guregu/null.v4" ) -const FluxMonitorTestSpec = ` +const FluxMonitorTestSpecTemplate = ` type = "fluxmonitor" schemaVersion = 1 -name = "example flux monitor spec" +name = "%s" contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" +externalJobID = "%s" threshold = 0.5 absoluteThreshold = 0.0 # optional @@ -68,11 +68,11 @@ answer1 [type=median index=0]; """ ` -const OCR1TestSpec = ` +const OCR1TestSpecTemplate = ` type = "offchainreporting" schemaVersion = 1 -name = "example OCR1 spec" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46" +name = "%s" +externalJobID = "%s" evmChainID = 0 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pBootstrapPeers = [ @@ -102,14 +102,14 @@ observationSource = """ """ ` -const OCR2TestSpec = ` +const OCR2TestSpecTemplate = ` type = "offchainreporting2" pluginType = "median" schemaVersion = 1 -name = "example OCR2 spec" +name = "%s" relay = "evm" contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" +externalJobID = "%s" observationSource = """ ds1 [type=bridge name=voter_turnout]; ds1_parse [type=jsonparse path="one,two"]; @@ -128,10 +128,10 @@ ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ ` -const BootstrapTestSpec = ` +const BootstrapTestSpecTemplate = ` type = "bootstrap" schemaVersion = 1 -name = "example Bootstrap spec" +name = "%s" contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" relay = "evm" [relayConfig] @@ -539,62 +539,68 @@ func Test_Service_ProposeJob(t *testing.T) { var ( idFluxMonitor = int64(1) remoteUUIDFluxMonitor = uuid.New() + nameAndExternalJobID = uuid.New() + spec = fmt.Sprintf(FluxMonitorTestSpecTemplate, nameAndExternalJobID, nameAndExternalJobID) argsFluxMonitor = &feeds.ProposeJobArgs{ FeedsManagerID: 1, RemoteUUID: remoteUUIDFluxMonitor, - Spec: FluxMonitorTestSpec, + Spec: spec, Version: 1, } jpFluxMonitor = feeds.JobProposal{ FeedsManagerID: 1, - Name: null.StringFrom("example flux monitor spec"), + Name: null.StringFrom(nameAndExternalJobID.String()), RemoteUUID: remoteUUIDFluxMonitor, Status: feeds.JobProposalStatusPending, } specFluxMonitor = feeds.JobProposalSpec{ - Definition: FluxMonitorTestSpec, + Definition: spec, Status: feeds.SpecStatusPending, Version: argsFluxMonitor.Version, JobProposalID: idFluxMonitor, } - idOCR1 = int64(2) - remoteUUIDOCR1 = uuid.New() - argsOCR1 = &feeds.ProposeJobArgs{ + idOCR1 = int64(2) + remoteUUIDOCR1 = uuid.New() + ocr1NameAndExternalJobID = uuid.New() + ocr1Spec = fmt.Sprintf(OCR1TestSpecTemplate, ocr1NameAndExternalJobID, ocr1NameAndExternalJobID) + argsOCR1 = &feeds.ProposeJobArgs{ FeedsManagerID: 1, RemoteUUID: remoteUUIDOCR1, - Spec: OCR1TestSpec, + Spec: ocr1Spec, Version: 1, } jpOCR1 = feeds.JobProposal{ FeedsManagerID: 1, - Name: null.StringFrom("example OCR1 spec"), + Name: null.StringFrom(ocr1NameAndExternalJobID.String()), RemoteUUID: remoteUUIDOCR1, Status: feeds.JobProposalStatusPending, } specOCR1 = feeds.JobProposalSpec{ - Definition: OCR1TestSpec, + Definition: ocr1Spec, Status: feeds.SpecStatusPending, Version: argsOCR1.Version, JobProposalID: idOCR1, } - idOCR2 = int64(3) - remoteUUIDOCR2 = uuid.New() - argsOCR2 = &feeds.ProposeJobArgs{ + idOCR2 = int64(3) + remoteUUIDOCR2 = uuid.New() + ocr2NameAndExternalJobID = uuid.New() + ocr2Spec = fmt.Sprintf(OCR2TestSpecTemplate, ocr2NameAndExternalJobID, ocr2NameAndExternalJobID) + argsOCR2 = &feeds.ProposeJobArgs{ FeedsManagerID: 1, RemoteUUID: remoteUUIDOCR2, - Spec: OCR2TestSpec, + Spec: ocr2Spec, Version: 1, } jpOCR2 = feeds.JobProposal{ FeedsManagerID: 1, - Name: null.StringFrom("example OCR2 spec"), + Name: null.StringFrom(ocr2NameAndExternalJobID.String()), RemoteUUID: remoteUUIDOCR2, Status: feeds.JobProposalStatusPending, } specOCR2 = feeds.JobProposalSpec{ - Definition: OCR2TestSpec, + Definition: ocr2Spec, Status: feeds.SpecStatusPending, Version: argsOCR2.Version, JobProposalID: idOCR2, @@ -602,20 +608,22 @@ func Test_Service_ProposeJob(t *testing.T) { idBootstrap = int64(4) remoteUUIDBootstrap = uuid.New() + bootstrapName = uuid.New() + bootstrapSpec = fmt.Sprintf(BootstrapTestSpecTemplate, bootstrapName) argsBootstrap = &feeds.ProposeJobArgs{ FeedsManagerID: 1, RemoteUUID: remoteUUIDBootstrap, - Spec: BootstrapTestSpec, + Spec: bootstrapSpec, Version: 1, } jpBootstrap = feeds.JobProposal{ FeedsManagerID: 1, - Name: null.StringFrom("example Bootstrap spec"), + Name: null.StringFrom(bootstrapName.String()), RemoteUUID: remoteUUIDBootstrap, Status: feeds.JobProposalStatusPending, } specBootstrap = feeds.JobProposalSpec{ - Definition: BootstrapTestSpec, + Definition: bootstrapSpec, Status: feeds.SpecStatusPending, Version: argsBootstrap.Version, JobProposalID: idBootstrap, @@ -702,7 +710,7 @@ func Test_Service_ProposeJob(t *testing.T) { name: "must be an ocr job to include bootstraps", before: func(svc *TestService) {}, args: &feeds.ProposeJobArgs{ - Spec: FluxMonitorTestSpec, + Spec: spec, Multiaddrs: pq.StringArray{"/dns4/example.com"}, }, wantErr: "only OCR job type supports multiaddr", @@ -1116,8 +1124,7 @@ answer1 [type=median index=0]; } func Test_Service_SyncNodeInfo(t *testing.T) { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) + p2pKey := keystest.NewP2PKeyV2(t) ocrKey, err := ocrkey.NewV2() require.NoError(t, err) diff --git a/core/services/fluxmonitorv2/contract_submitter.go b/core/services/fluxmonitorv2/contract_submitter.go index d60f5b70e01..8f3f40c309d 100644 --- a/core/services/fluxmonitorv2/contract_submitter.go +++ b/core/services/fluxmonitorv2/contract_submitter.go @@ -1,6 +1,7 @@ package fluxmonitorv2 import ( + "context" "math/big" "github.com/pkg/errors" @@ -16,7 +17,7 @@ var FluxAggregatorABI = evmtypes.MustGetABI(flux_aggregator_wrapper.FluxAggregat // ContractSubmitter defines an interface to submit an eth tx. type ContractSubmitter interface { - Submit(roundID *big.Int, submission *big.Int, idempotencyKey *string) error + Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error } // FluxAggregatorContractSubmitter submits the polled answer in an eth tx. @@ -50,7 +51,7 @@ func NewFluxAggregatorContractSubmitter( // Submit submits the answer by writing a EthTx for the txmgr to // pick up -func (c *FluxAggregatorContractSubmitter) Submit(roundID *big.Int, submission *big.Int, idempotencyKey *string) error { +func (c *FluxAggregatorContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { fromAddress, err := c.keyStore.GetRoundRobinAddress(c.chainID) if err != nil { return err @@ -62,7 +63,7 @@ func (c *FluxAggregatorContractSubmitter) Submit(roundID *big.Int, submission *b } return errors.Wrap( - c.orm.CreateEthTransaction(fromAddress, c.Address(), payload, c.gasLimit, idempotencyKey), + c.orm.CreateEthTransaction(ctx, fromAddress, c.Address(), payload, c.gasLimit, idempotencyKey), "failed to send Eth transaction", ) } diff --git a/core/services/fluxmonitorv2/contract_submitter_test.go b/core/services/fluxmonitorv2/contract_submitter_test.go index 7c282e3190c..c3b2ca7e715 100644 --- a/core/services/fluxmonitorv2/contract_submitter_test.go +++ b/core/services/fluxmonitorv2/contract_submitter_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -35,8 +36,8 @@ func TestFluxAggregatorContractSubmitter_Submit(t *testing.T) { fluxAggregator.On("Address").Return(toAddress) idempotencyKey := uuid.New().String() - orm.On("CreateEthTransaction", fromAddress, toAddress, payload, gasLimit, &idempotencyKey).Return(nil) + orm.On("CreateEthTransaction", mock.Anything, fromAddress, toAddress, payload, gasLimit, &idempotencyKey).Return(nil) - err = submitter.Submit(roundID, submission, &idempotencyKey) + err = submitter.Submit(testutils.Context(t), roundID, submission, &idempotencyKey) assert.NoError(t, err) } diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go index 0564eecaee4..d380122f715 100644 --- a/core/services/fluxmonitorv2/delegate.go +++ b/core/services/fluxmonitorv2/delegate.go @@ -2,6 +2,7 @@ package fluxmonitorv2 import ( "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -59,7 +60,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the flux monitor service for the job spec -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { if jb.FluxMonitorSpec == nil { return nil, errors.Errorf("Delegate expects a *job.FluxMonitorSpec to be present, got %v", jb) } diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 0b09655707d..fe8a22d4177 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -587,6 +587,8 @@ func (fm *FluxMonitor) respondToAnswerUpdatedLog(log flux_aggregator_wrapper.Flu // need to poll and submit an answer to the contract regardless of the deviation. func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggregatorNewRound, lb log.Broadcast) { started := time.Now() + ctx, cancel := utils.StopChan(fm.chStop).NewCtx() + defer cancel() newRoundLogger := fm.logger.With( "round", log.RoundId, @@ -743,7 +745,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr }) // Call the v2 pipeline to execute a new job run - run, results, err := fm.runner.ExecuteRun(context.Background(), fm.spec, vars, fm.logger) + run, results, err := fm.runner.ExecuteRun(ctx, fm.spec, vars, fm.logger) if err != nil { newRoundLogger.Errorw(fmt.Sprintf("error executing new run for job ID %v name %v", fm.spec.JobID, fm.spec.JobName), "err", err) return @@ -772,7 +774,7 @@ func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggr if err2 := fm.runner.InsertFinishedRun(run, false, pg.WithQueryer(tx)); err2 != nil { return err2 } - if err2 := fm.queueTransactionForTxm(tx, run.ID, answer, roundState.RoundId, &log); err2 != nil { + if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, &log); err2 != nil { return err2 } return fm.logBroadcaster.MarkConsumed(lb, pg.WithQueryer(tx)) @@ -811,6 +813,8 @@ func (fm *FluxMonitor) checkEligibilityAndAggregatorFunding(roundState flux_aggr func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker *DeviationChecker, broadcast log.Broadcast) { started := time.Now() + ctx, cancel := utils.StopChan(fm.chStop).NewCtx() + defer cancel() l := fm.logger.With( "threshold", deviationChecker.Thresholds.Rel, @@ -946,7 +950,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker }, }) - run, results, err := fm.runner.ExecuteRun(context.Background(), fm.spec, vars, fm.logger) + run, results, err := fm.runner.ExecuteRun(ctx, fm.spec, vars, fm.logger) if err != nil { l.Errorw("can't fetch answer", "err", err) fm.jobORM.TryRecordError(fm.spec.JobID, "Error polling") @@ -996,7 +1000,7 @@ func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker if err2 := fm.runner.InsertFinishedRun(run, true, pg.WithQueryer(tx)); err2 != nil { return err2 } - if err2 := fm.queueTransactionForTxm(tx, run.ID, answer, roundState.RoundId, nil); err2 != nil { + if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, nil); err2 != nil { return err2 } if broadcast != nil { @@ -1036,7 +1040,7 @@ func (fm *FluxMonitor) isValidSubmission(l logger.Logger, answer decimal.Decimal pipeline.PromPipelineTaskExecutionTime.WithLabelValues(fmt.Sprintf("%d", jobId), jobName, "", job.FluxMonitor.String()).Set(float64(elapsed)) pipeline.PromPipelineRunErrors.WithLabelValues(fmt.Sprintf("%d", jobId), jobName).Inc() pipeline.PromPipelineRunTotalTimeToCompletion.WithLabelValues(fmt.Sprintf("%d", jobId), jobName).Set(float64(elapsed)) - pipeline.PromPipelineTasksTotalFinished.WithLabelValues(fmt.Sprintf("%d", jobId), jobName, "", job.FluxMonitor.String(), "error").Inc() + pipeline.PromPipelineTasksTotalFinished.WithLabelValues(fmt.Sprintf("%d", jobId), jobName, "", job.FluxMonitor.String(), "", "error").Inc() return false } @@ -1072,11 +1076,12 @@ func (fm *FluxMonitor) initialRoundState() flux_aggregator_wrapper.OracleRoundSt return latestRoundState } -func (fm *FluxMonitor) queueTransactionForTxm(tx pg.Queryer, runID int64, answer decimal.Decimal, roundID uint32, log *flux_aggregator_wrapper.FluxAggregatorNewRound) error { +func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx pg.Queryer, runID int64, answer decimal.Decimal, roundID uint32, log *flux_aggregator_wrapper.FluxAggregatorNewRound) error { // Use pipeline run ID to generate globally unique key that can correlate this run to a Tx idempotencyKey := fmt.Sprintf("fluxmonitor-%d", runID) // Submit the Eth Tx err := fm.contractSubmitter.Submit( + ctx, new(big.Int).SetInt64(int64(roundID)), answer.BigInt(), &idempotencyKey, diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 27d40cd69c7..83ffee8ac57 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -278,7 +278,7 @@ func withORM(orm fluxmonitorv2.ORM) func(*setupOptions) { func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { db := pgtest.NewSqlxDB(t) ethKeyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)).Eth() - _, nodeAddr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr } @@ -287,7 +287,7 @@ func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { func setupFullDBWithKey(t *testing.T, name string) (*sqlx.DB, common.Address) { cfg, db := heavyweight.FullTestDBV2(t, name, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, nodeAddr := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) return db, nodeAddr } @@ -474,7 +474,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) { }). Once() tm.contractSubmitter. - On("Submit", big.NewInt(reportableRoundID), big.NewInt(answers.polledAnswer), buildIdempotencyKey(run.ID)). + On("Submit", mock.Anything, big.NewInt(reportableRoundID), big.NewInt(answers.polledAnswer), buildIdempotencyKey(run.ID)). Return(nil). Once() @@ -609,7 +609,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { args.Get(0).(*pipeline.Run).ID = 1 }).Once() tm.contractSubmitter. - On("Submit", big.NewInt(1), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). + On("Submit", mock.Anything, big.NewInt(1), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). Return(nil). Once() @@ -649,7 +649,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { args.Get(0).(*pipeline.Run).ID = 2 }).Once() tm.contractSubmitter. - On("Submit", big.NewInt(3), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). + On("Submit", mock.Anything, big.NewInt(3), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). Return(nil). Once() tm.orm. @@ -688,7 +688,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { args.Get(0).(*pipeline.Run).ID = 3 }).Once() tm.contractSubmitter. - On("Submit", big.NewInt(4), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). + On("Submit", mock.Anything, big.NewInt(4), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). Return(nil). Once() tm.orm. @@ -1515,7 +1515,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { args.Get(0).(*pipeline.Run).ID = 1 }) tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil).Once() - tm.contractSubmitter.On("Submit", big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() + tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", contractAddress, @@ -1642,7 +1642,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { Run(func(args mock.Arguments) { args.Get(0).(*pipeline.Run).ID = 1 }) - tm.contractSubmitter.On("Submit", big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() + tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", contractAddress, @@ -1738,7 +1738,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { Run(func(args mock.Arguments) { args.Get(0).(*pipeline.Run).ID = 1 }) - tm.contractSubmitter.On("Submit", big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() + tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", contractAddress, @@ -1811,7 +1811,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { Once() // and that should result in a new submission - tm.contractSubmitter.On("Submit", big.NewInt(olderRoundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() + tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(olderRoundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() tm.orm. On("UpdateFluxMonitorRoundStats", @@ -1919,7 +1919,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { }). Once() tm.contractSubmitter. - On("Submit", big.NewInt(int64(roundID)), answerBigInt, buildIdempotencyKey(runID)). + On("Submit", mock.Anything, big.NewInt(int64(roundID)), answerBigInt, buildIdempotencyKey(runID)). Return(nil). Once() diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 5b6a94cac58..2c45ed5ad89 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -21,10 +21,11 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/onsi/gomega" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -523,8 +524,9 @@ func TestFluxMonitor_Deviation(t *testing.T) { initialBalance := currentBalance(t, &fa).Int64() jobResponse := cltest.CreateJobViaWeb2(t, app, string(requestBody)) - jobId, err := strconv.Atoi(jobResponse.ID) + i, err := strconv.ParseInt(jobResponse.ID, 10, 32) require.NoError(t, err) + jobID := int32(i) // Waiting for flux monitor to finish Register process in log broadcaster // and then to have log broadcaster backfill logs after the debounceResubscribe period of ~ 1 sec @@ -559,7 +561,7 @@ func TestFluxMonitor_Deviation(t *testing.T) { // Need to wait until NewRound log is consumed - otherwise there is a chance // it will arrive after the next answer is submitted, and cause // DeleteFluxMonitorRoundsBackThrough to delete previous stats - checkLogWasConsumed(t, fa, app.GetSqlxDB(), int32(jobId), receiptBlock, app.GetConfig().Database()) + checkLogWasConsumed(t, fa, app.GetSqlxDB(), jobID, receiptBlock, app.GetConfig().Database()) lggr.Info("Updating price to 103") // Change reported price to a value outside the deviation @@ -588,7 +590,7 @@ func TestFluxMonitor_Deviation(t *testing.T) { // Need to wait until NewRound log is consumed - otherwise there is a chance // it will arrive after the next answer is submitted, and cause // DeleteFluxMonitorRoundsBackThrough to delete previous stats - checkLogWasConsumed(t, fa, app.GetSqlxDB(), int32(jobId), receiptBlock, app.GetConfig().Database()) + checkLogWasConsumed(t, fa, app.GetSqlxDB(), jobID, receiptBlock, app.GetConfig().Database()) // Should not received a submission as it is inside the deviation reportPrice.Store(104) diff --git a/core/services/fluxmonitorv2/key_store_test.go b/core/services/fluxmonitorv2/key_store_test.go index 8445ea55516..ed0485d3b3c 100644 --- a/core/services/fluxmonitorv2/key_store_test.go +++ b/core/services/fluxmonitorv2/key_store_test.go @@ -43,7 +43,7 @@ func TestKeyStore_GetRoundRobinAddress(t *testing.T) { cfg := pgtest.NewQConfig(true) ethKeyStore := cltest.NewKeyStore(t, db, cfg).Eth() - _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore) ks := fluxmonitorv2.NewKeyStore(ethKeyStore) diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go index 6214255ff66..03540a6cb1c 100644 --- a/core/services/fluxmonitorv2/mocks/contract_submitter.go +++ b/core/services/fluxmonitorv2/mocks/contract_submitter.go @@ -1,8 +1,9 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( + context "context" big "math/big" mock "github.com/stretchr/testify/mock" @@ -13,13 +14,13 @@ type ContractSubmitter struct { mock.Mock } -// Submit provides a mock function with given fields: roundID, submission, idempotencyKey -func (_m *ContractSubmitter) Submit(roundID *big.Int, submission *big.Int, idempotencyKey *string) error { - ret := _m.Called(roundID, submission, idempotencyKey) +// Submit provides a mock function with given fields: ctx, roundID, submission, idempotencyKey +func (_m *ContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { + ret := _m.Called(ctx, roundID, submission, idempotencyKey) var r0 error - if rf, ok := ret.Get(0).(func(*big.Int, *big.Int, *string) error); ok { - r0 = rf(roundID, submission, idempotencyKey) + if rf, ok := ret.Get(0).(func(context.Context, *big.Int, *big.Int, *string) error); ok { + r0 = rf(ctx, roundID, submission, idempotencyKey) } else { r0 = ret.Error(0) } @@ -27,13 +28,12 @@ func (_m *ContractSubmitter) Submit(roundID *big.Int, submission *big.Int, idemp return r0 } -type mockConstructorTestingTNewContractSubmitter interface { +// NewContractSubmitter creates a new instance of ContractSubmitter. 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 NewContractSubmitter(t interface { mock.TestingT Cleanup(func()) -} - -// NewContractSubmitter creates a new instance of ContractSubmitter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewContractSubmitter(t mockConstructorTestingTNewContractSubmitter) *ContractSubmitter { +}) *ContractSubmitter { mock := &ContractSubmitter{} mock.Mock.Test(t) diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go index 6fbb31e1201..08ad0f5b3f7 100644 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ b/core/services/fluxmonitorv2/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -97,13 +97,12 @@ func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { return r0, r1 } -type mockConstructorTestingTNewFlags interface { +// NewFlags creates a new instance of Flags. 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 NewFlags(t interface { mock.TestingT Cleanup(func()) -} - -// NewFlags creates a new instance of Flags. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFlags(t mockConstructorTestingTNewFlags) *Flags { +}) *Flags { mock := &Flags{} mock.Mock.Test(t) diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index faddb3850f3..c409a987e02 100644 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ b/core/services/fluxmonitorv2/mocks/key_store_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -75,13 +75,12 @@ func (_m *KeyStoreInterface) GetRoundRobinAddress(chainID *big.Int, addrs ...com return r0, r1 } -type mockConstructorTestingTNewKeyStoreInterface interface { +// NewKeyStoreInterface creates a new instance of KeyStoreInterface. 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 NewKeyStoreInterface(t interface { mock.TestingT Cleanup(func()) -} - -// NewKeyStoreInterface creates a new instance of KeyStoreInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewKeyStoreInterface(t mockConstructorTestingTNewKeyStoreInterface) *KeyStoreInterface { +}) *KeyStoreInterface { mock := &KeyStoreInterface{} mock.Mock.Test(t) diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go index 1f2303fbf1a..5080f19edf0 100644 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ b/core/services/fluxmonitorv2/mocks/orm.go @@ -1,10 +1,14 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( + context "context" + common "github.com/ethereum/go-ethereum/common" + fluxmonitorv2 "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" + mock "github.com/stretchr/testify/mock" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -39,13 +43,13 @@ func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { return r0, r1 } -// CreateEthTransaction provides a mock function with given fields: fromAddress, toAddress, payload, gasLimit, idempotencyKey -func (_m *ORM) CreateEthTransaction(fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error { - ret := _m.Called(fromAddress, toAddress, payload, gasLimit, idempotencyKey) +// CreateEthTransaction provides a mock function with given fields: ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey +func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error { + ret := _m.Called(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) var r0 error - if rf, ok := ret.Get(0).(func(common.Address, common.Address, []byte, uint32, *string) error); ok { - r0 = rf(fromAddress, toAddress, payload, gasLimit, idempotencyKey) + if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address, []byte, uint32, *string) error); ok { + r0 = rf(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) } else { r0 = ret.Error(0) } @@ -136,13 +140,12 @@ func (_m *ORM) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID ui return r0 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/fluxmonitorv2/orm.go b/core/services/fluxmonitorv2/orm.go index 70ebd2e7020..61395e8708a 100644 --- a/core/services/fluxmonitorv2/orm.go +++ b/core/services/fluxmonitorv2/orm.go @@ -1,6 +1,7 @@ package fluxmonitorv2 import ( + "context" "database/sql" "github.com/ethereum/go-ethereum/common" @@ -15,7 +16,7 @@ import ( ) type transmitter interface { - CreateTransaction(txRequest txmgr.TxRequest, qopts ...pg.QOpt) (tx txmgr.Tx, err error) + CreateTransaction(ctx context.Context, txRequest txmgr.TxRequest) (tx txmgr.Tx, err error) } //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore @@ -26,7 +27,7 @@ type ORM interface { DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, error) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint, qopts ...pg.QOpt) error - CreateEthTransaction(fromAddress, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error + CreateEthTransaction(ctx context.Context, fromAddress, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error CountFluxMonitorRoundStats() (count int, err error) } @@ -114,6 +115,7 @@ func (o *orm) CountFluxMonitorRoundStats() (count int, err error) { // CreateEthTransaction creates an ethereum transaction for the Txm to pick up func (o *orm) CreateEthTransaction( + ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, @@ -121,7 +123,7 @@ func (o *orm) CreateEthTransaction( idempotencyKey *string, ) (err error) { - _, err = o.txm.CreateTransaction(txmgr.TxRequest{ + _, err = o.txm.CreateTransaction(ctx, txmgr.TxRequest{ IdempotencyKey: idempotencyKey, FromAddress: fromAddress, ToAddress: toAddress, diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index a24f516c7f0..3bebc150c82 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "gopkg.in/guregu/null.v4" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" @@ -180,13 +181,13 @@ func TestORM_CreateEthTransaction(t *testing.T) { txm = txmmocks.NewMockEvmTxManager(t) orm = fluxmonitorv2.NewORM(db, logger.TestLogger(t), cfg, txm, strategy, txmgr.TransmitCheckerSpec{}) - _, from = cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, from = cltest.MustInsertRandomKey(t, ethKeyStore) to = testutils.NewAddress() payload = []byte{1, 0, 0} gasLimit = uint32(21000) ) idempotencyKey := uuid.New().String() - txm.On("CreateTransaction", txmgr.TxRequest{ + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ IdempotencyKey: &idempotencyKey, FromAddress: from, ToAddress: to, @@ -196,5 +197,5 @@ func TestORM_CreateEthTransaction(t *testing.T) { Strategy: strategy, }).Return(txmgr.Tx{}, nil).Once() - require.NoError(t, orm.CreateEthTransaction(from, to, payload, gasLimit, &idempotencyKey)) + require.NoError(t, orm.CreateEthTransaction(testutils.Context(t), from, to, payload, gasLimit, &idempotencyKey)) } diff --git a/core/services/functions/external_adapter_client.go b/core/services/functions/external_adapter_client.go index fc12406e442..db4fed30e5f 100644 --- a/core/services/functions/external_adapter_client.go +++ b/core/services/functions/external_adapter_client.go @@ -129,6 +129,7 @@ func (ea *externalAdapterClient) RunComputation( nodeProvidedSecrets string, requestData *RequestData, ) (userResult, userError []byte, domains []string, err error) { + requestData.Secrets = nil // secrets are passed in nodeProvidedSecrets payload := requestPayload{ Endpoint: "lambda", diff --git a/core/services/functions/external_adapter_client_test.go b/core/services/functions/external_adapter_client_test.go index a0d6d461099..9fd40ba8280 100644 --- a/core/services/functions/external_adapter_client_test.go +++ b/core/services/functions/external_adapter_client_test.go @@ -166,7 +166,7 @@ func TestRunComputation_CorrectAdapterRequest(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) assert.NoError(t, err) - expectedData := `{"source":"abcd","language":7,"codeLocation":42,"secrets":"qrvM","secretsLocation":88,"args":["arg1","arg2"]}` + expectedData := `{"source":"abcd","language":7,"codeLocation":42,"secretsLocation":88,"args":["arg1","arg2"]}` expectedBody := fmt.Sprintf(`{"endpoint":"lambda","requestId":"requestID1234","jobName":"TestJob","subscriptionOwner":"SubOwner","subscriptionId":1,"flags":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"nodeProvidedSecrets":"secRETS","data":%s}`, expectedData) assert.Equal(t, expectedBody, string(body)) diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 084d1530a76..b76eb0a1c05 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "math" - "reflect" "sync" "time" @@ -16,9 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_oracle" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" @@ -33,7 +29,6 @@ import ( ) var ( - _ log.Listener = &FunctionsListener{} _ job.ServiceCtx = &FunctionsListener{} sizeBuckets = []float64{ @@ -45,51 +40,51 @@ var ( 1024 * 256, } - promOracleEvent = promauto.NewCounterVec(prometheus.CounterOpts{ - Name: "functions_oracle_event", - Help: "Metric to track received oracle events", - }, []string{"oracle", "event"}) + promRequestReceived = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "functions_request_received", + Help: "Metric to track received request events", + }, []string{"router"}) promRequestInternalError = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_internal_error", Help: "Metric to track internal errors", - }, []string{"oracle"}) + }, []string{"router"}) promRequestComputationError = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_computation_error", Help: "Metric to track computation errors", - }, []string{"oracle"}) + }, []string{"router"}) promRequestComputationSuccess = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_computation_success", Help: "Metric to track number of computed requests", - }, []string{"oracle"}) + }, []string{"router"}) promRequestTimeout = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_timeout", Help: "Metric to track number of timed out requests", - }, []string{"oracle"}) + }, []string{"router"}) promRequestConfirmed = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_confirmed", Help: "Metric to track number of confirmed requests", - }, []string{"oracle", "responseType"}) + }, []string{"router"}) promRequestDataSize = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "functions_request_data_size", Help: "Metric to track request data size", Buckets: sizeBuckets, - }, []string{"oracle"}) + }, []string{"router"}) promComputationResultSize = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "functions_request_computation_result_size", Help: "Metric to track computation result size in bytes", - }, []string{"oracle"}) + }, []string{"router"}) promComputationErrorSize = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "functions_request_computation_error_size", Help: "Metric to track computation error size in bytes", - }, []string{"oracle"}) + }, []string{"router"}) promComputationDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "functions_request_computation_duration", @@ -103,12 +98,12 @@ var ( float64(30 * time.Second), float64(60 * time.Second), }, - }, []string{"oracle"}) + }, []string{"router"}) promPrunedRequests = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "functions_request_pruned", Help: "Metric to track number of requests pruned from the DB", - }, []string{"oracle"}) + }, []string{"router"}) ) const ( @@ -126,9 +121,7 @@ type FunctionsListener struct { contractAddressHex string job job.Job bridgeAccessor BridgeAccessor - logBroadcaster log.Broadcaster shutdownWaitGroup sync.WaitGroup - mbOracleEvents *utils.Mailbox[log.Broadcast] serviceContext context.Context serviceCancel context.CancelFunc chStop chan struct{} @@ -136,7 +129,6 @@ type FunctionsListener struct { pluginConfig config.PluginConfig s4Storage s4.Storage logger logger.Logger - mailMon *utils.MailboxMonitor urlsMonEndpoint commontypes.MonitoringEndpoint decryptor threshold.Decryptor logPollerWrapper evmrelayTypes.LogPollerWrapper @@ -160,9 +152,7 @@ func NewFunctionsListener( pluginORM ORM, pluginConfig config.PluginConfig, s4Storage s4.Storage, - logBroadcaster log.Broadcaster, lggr logger.Logger, - mailMon *utils.MailboxMonitor, urlsMonEndpoint commontypes.MonitoringEndpoint, decryptor threshold.Decryptor, logPollerWrapper evmrelayTypes.LogPollerWrapper, @@ -172,14 +162,11 @@ func NewFunctionsListener( contractAddressHex: contractAddressHex, job: job, bridgeAccessor: bridgeAccessor, - logBroadcaster: logBroadcaster, - mbOracleEvents: utils.NewHighCapacityMailbox[log.Broadcast](), chStop: make(chan struct{}), pluginORM: pluginORM, pluginConfig: pluginConfig, s4Storage: s4Storage, logger: lggr, - mailMon: mailMon, urlsMonEndpoint: urlsMonEndpoint, decryptor: decryptor, logPollerWrapper: logPollerWrapper, @@ -190,34 +177,13 @@ func NewFunctionsListener( func (l *FunctionsListener) Start(context.Context) error { return l.StartOnce("FunctionsListener", func() error { l.serviceContext, l.serviceCancel = context.WithCancel(context.Background()) - contractAddress := common.HexToAddress(l.contractAddressHex) - var unsubscribeLogs func() switch l.pluginConfig.ContractVersion { - case 0: - oracleContract, err := ocr2dr_oracle.NewOCR2DROracle(contractAddress, l.client) - if err != nil { - return err - } - unsubscribeLogs = l.logBroadcaster.Register(l, log.ListenerOpts{ - Contract: oracleContract.Address(), - ParseLog: oracleContract.ParseLog, - LogsWithTopics: map[common.Hash][][]log.Topic{ - ocr2dr_oracle.OCR2DROracleOracleRequest{}.Topic(): {}, - ocr2dr_oracle.OCR2DROracleOracleResponse{}.Topic(): {}, - ocr2dr_oracle.OCR2DROracleUserCallbackError{}.Topic(): {}, - ocr2dr_oracle.OCR2DROracleUserCallbackRawError{}.Topic(): {}, - ocr2dr_oracle.OCR2DROracleResponseTransmitted{}.Topic(): {}, - }, - MinIncomingConfirmations: l.pluginConfig.MinIncomingConfirmations, - }) - l.shutdownWaitGroup.Add(1) - go l.processOracleEventsV0() case 1: l.shutdownWaitGroup.Add(1) go l.processOracleEventsV1() default: - return errors.New("Functions: unsupported PluginConfig.ContractVersion") + return fmt.Errorf("unsupported contract version: %d", l.pluginConfig.ContractVersion) } if l.pluginConfig.ListenerEventHandlerTimeoutSec == 0 { @@ -228,14 +194,8 @@ func (l *FunctionsListener) Start(context.Context) error { go l.pruneRequests() go func() { <-l.chStop - if unsubscribeLogs != nil { - unsubscribeLogs() // v0 only - } l.shutdownWaitGroup.Done() }() - - l.mailMon.Monitor(l.mbOracleEvents, "FunctionsListener", "OracleEvents", fmt.Sprint(l.job.ID)) - return nil }) } @@ -246,94 +206,10 @@ func (l *FunctionsListener) Close() error { l.serviceCancel() close(l.chStop) l.shutdownWaitGroup.Wait() - - return l.mbOracleEvents.Close() + return nil }) } -// HandleLog implements log.Listener -func (l *FunctionsListener) HandleLog(lb log.Broadcast) { - log := lb.DecodedLog() - if log == nil || reflect.ValueOf(log).IsNil() { - l.logger.Error("HandleLog: ignoring nil value") - return - } - - switch log := log.(type) { - case *ocr2dr_oracle.OCR2DROracleOracleRequest, *ocr2dr_oracle.OCR2DROracleOracleResponse, *ocr2dr_oracle.OCR2DROracleUserCallbackError, *ocr2dr_oracle.OCR2DROracleUserCallbackRawError, *ocr2dr_oracle.OCR2DROracleResponseTransmitted, *functions_coordinator.FunctionsCoordinatorOracleRequest, *functions_coordinator.FunctionsCoordinatorOracleResponse: - wasOverCapacity := l.mbOracleEvents.Deliver(lb) - if wasOverCapacity { - l.logger.Error("OracleRequest log mailbox is over capacity - dropped the oldest log") - } - default: - l.logger.Errorf("Unexpected log type %T", log) - } -} - -// JobID() complies with log.Listener -func (l *FunctionsListener) JobID() int32 { - return l.job.ID -} - -func (l *FunctionsListener) processOracleEventsV0() { - defer l.shutdownWaitGroup.Done() - for { - select { - case <-l.chStop: - return - case <-l.mbOracleEvents.Notify(): - for { - select { - case <-l.chStop: - return - default: - } - lb, exists := l.mbOracleEvents.Retrieve() - if !exists { - break - } - was, err := l.logBroadcaster.WasAlreadyConsumed(lb) - if err != nil { - l.logger.Errorw("Could not determine if log was already consumed", "err", err) - continue - } else if was { - continue - } - - log := lb.DecodedLog() - if log == nil || reflect.ValueOf(log).IsNil() { - l.logger.Error("processOracleEvents: ignoring nil value") - continue - } - - switch log := log.(type) { - // Version 0 - case *ocr2dr_oracle.OCR2DROracleOracleRequest: - promOracleEvent.WithLabelValues(log.Raw.Address.Hex(), "OracleRequest").Inc() - l.shutdownWaitGroup.Add(1) - go l.handleOracleRequestV0(log, lb) - case *ocr2dr_oracle.OCR2DROracleOracleResponse: - promOracleEvent.WithLabelValues(log.Raw.Address.Hex(), "OracleResponse").Inc() - l.shutdownWaitGroup.Add(1) - go l.handleOracleResponseV0("OracleResponse", log.RequestId, lb) - case *ocr2dr_oracle.OCR2DROracleUserCallbackError: - promOracleEvent.WithLabelValues(log.Raw.Address.Hex(), "UserCallbackError").Inc() - l.shutdownWaitGroup.Add(1) - go l.handleOracleResponseV0("UserCallbackError", log.RequestId, lb) - case *ocr2dr_oracle.OCR2DROracleUserCallbackRawError: - promOracleEvent.WithLabelValues(log.Raw.Address.Hex(), "UserCallbackRawError").Inc() - l.shutdownWaitGroup.Add(1) - go l.handleOracleResponseV0("UserCallbackRawError", log.RequestId, lb) - case *ocr2dr_oracle.OCR2DROracleResponseTransmitted: - promOracleEvent.WithLabelValues(log.Raw.Address.Hex(), "ResponseTransmitted").Inc() - default: - l.logger.Warnf("Unexpected log type %T", log) - } - } - } - } -} - func (l *FunctionsListener) processOracleEventsV1() { defer l.shutdownWaitGroup.Done() freqMillis := l.pluginConfig.ListenerEventsCheckFrequencyMillis @@ -429,6 +305,7 @@ func (l *FunctionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleR return } + promRequestReceived.WithLabelValues(l.contractAddressHex).Inc() promRequestDataSize.WithLabelValues(l.contractAddressHex).Observe(float64(len(request.Data))) requestData, err := l.parseCBOR(request.RequestId, request.Data, l.getMaxCBORsize(request.Flags)) if err != nil { @@ -438,34 +315,6 @@ func (l *FunctionsListener) handleOracleRequestV1(request *evmrelayTypes.OracleR l.handleRequest(ctx, request.RequestId, request.SubscriptionId, request.SubscriptionOwner, request.Flags, requestData) } -// deprecated -func (l *FunctionsListener) handleOracleRequestV0(request *ocr2dr_oracle.OCR2DROracleOracleRequest, lb log.Broadcast) { - defer l.shutdownWaitGroup.Done() - ctx, cancel := l.getNewHandlerContext() - defer cancel() - l.logger.Infow("oracle request received", "requestID", formatRequestId(request.RequestId)) - - newReq := &Request{RequestID: request.RequestId, RequestTxHash: &request.Raw.TxHash, ReceivedAt: time.Now()} - if err := l.pluginORM.CreateRequest(newReq, pg.WithParentCtx(ctx)); err != nil { - if errors.Is(err, ErrDuplicateRequestID) { - l.logger.Warnw("received a log with duplicate request ID", "requestID", formatRequestId(request.RequestId), "err", err) - l.markLogConsumed(lb, pg.WithParentCtx(ctx)) - } else { - l.logger.Errorw("failed to create a DB entry for new request", "requestID", formatRequestId(request.RequestId), "err", err) - } - return - } - l.markLogConsumed(lb, pg.WithParentCtx(ctx)) - - promRequestDataSize.WithLabelValues(l.contractAddressHex).Observe(float64(len(request.Data))) - requestData, err := l.parseCBOR(request.RequestId, request.Data, l.pluginConfig.MaxRequestSizeBytes) - if err != nil { - l.setError(ctx, request.RequestId, USER_ERROR, []byte(err.Error())) - return - } - l.handleRequest(ctx, request.RequestId, request.SubscriptionId, request.SubscriptionOwner, [32]byte{}, requestData) -} - func (l *FunctionsListener) parseCBOR(requestId RequestID, cborData []byte, maxSizeBytes uint32) (*RequestData, error) { if maxSizeBytes > 0 && uint32(len(cborData)) > maxSizeBytes { l.logger.Errorw("request too big", "requestID", formatRequestId(requestId), "requestSize", len(cborData), "maxRequestSize", maxSizeBytes) @@ -490,15 +339,6 @@ func (l *FunctionsListener) handleRequest(ctx context.Context, requestID Request requestIDStr := formatRequestId(requestID) l.logger.Infow("processing request", "requestID", requestIDStr) - if l.pluginConfig.ContractVersion == 1 && l.pluginConfig.EnableRequestSignatureCheck { - err := VerifyRequestSignature(subscriptionOwner, requestData) - if err != nil { - l.logger.Errorw("invalid request signature", "requestID", requestIDStr, "err", err) - l.setError(ctx, requestID, USER_ERROR, []byte(err.Error())) - return - } - } - eaClient, err := l.bridgeAccessor.NewExternalAdapterClient() if err != nil { l.logger.Errorw("failed to create ExternalAdapterClient", "requestID", requestIDStr, "err", err) @@ -569,26 +409,7 @@ func (l *FunctionsListener) handleOracleResponseV1(response *evmrelayTypes.Oracl if err := l.pluginORM.SetConfirmed(response.RequestId, pg.WithParentCtx(ctx)); err != nil { l.logger.Errorw("setting CONFIRMED state failed", "requestID", formatRequestId(response.RequestId), "err", err) } - promRequestConfirmed.WithLabelValues(l.contractAddressHex, "OracleResponse").Inc() -} - -func (l *FunctionsListener) handleOracleResponseV0(responseType string, requestID [32]byte, lb log.Broadcast) { - defer l.shutdownWaitGroup.Done() - l.logger.Infow("oracle response received", "type", responseType, "requestID", formatRequestId(requestID)) - - ctx, cancel := l.getNewHandlerContext() - defer cancel() - if err := l.pluginORM.SetConfirmed(requestID, pg.WithParentCtx(ctx)); err != nil { - l.logger.Errorw("setting CONFIRMED state failed", "requestID", formatRequestId(requestID), "err", err) - } - promRequestConfirmed.WithLabelValues(l.contractAddressHex, responseType).Inc() - l.markLogConsumed(lb, pg.WithParentCtx(ctx)) -} - -func (l *FunctionsListener) markLogConsumed(lb log.Broadcast, qopts ...pg.QOpt) { - if err := l.logBroadcaster.MarkConsumed(lb, qopts...); err != nil { - l.logger.Errorw("unable to mark log consumed", "err", err, "log", lb.String()) - } + promRequestConfirmed.WithLabelValues(l.contractAddressHex).Inc() } func (l *FunctionsListener) timeoutRequests() { @@ -707,7 +528,7 @@ func (l *FunctionsListener) getSecrets(ctx context.Context, eaClient ExternalAda return "", nil, errors.Wrap(err, "failed to fetch encrypted secrets") } if len(userError) != 0 { - l.logger.Debugw("no valid threshold encrypted secrets detected, falling back to legacy secrets", "requestID", requestIDStr, "err", string(userError)) + return "", errors.New(string(userError)), nil } secrets = thresholdEncSecrets case LocationDONHosted: diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index a06fcf3e3b2..6f0badd6e11 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -1,8 +1,8 @@ package functions_test import ( - "encoding/hex" "encoding/json" + "errors" "fmt" "math/big" "sync" @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/fxamacker/cbor/v2" "github.com/google/uuid" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -19,9 +18,7 @@ import ( decryptionPlugin "github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin" - cl_cbor "github.com/smartcontractkit/chainlink/v2/core/cbor" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_oracle" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -53,32 +50,30 @@ type FunctionsListenerUniverse struct { bridgeAccessor *functions_mocks.BridgeAccessor eaClient *functions_mocks.ExternalAdapterClient pluginORM *functions_mocks.ORM - logBroadcaster *log_mocks.Broadcaster - ingressClient *sync_mocks.TelemetryIngressClient + ingressClient *sync_mocks.TelemetryService decryptor *threshold_mocks.Decryptor logPollerWrapper *evmrelay_mocks.LogPollerWrapper - contractVersion uint32 } func ptr[T any](t T) *T { return &t } var ( - RequestID functions_service.RequestID = newRequestID() - RequestIDStr = fmt.Sprintf("0x%x", [32]byte(RequestID)) - SubscriptionOwner common.Address = common.BigToAddress(big.NewInt(42069)) - SubscriptionID = uint64(5) - ResultBytes = []byte{0xab, 0xcd} - ErrorBytes = []byte{0xff, 0x11} - Domains = []string{"github.com", "google.com"} - EncryptedSecretsUrls []byte = []byte{0x11, 0x22} - EncryptedSecrets []byte = []byte(`{"TDH2Ctxt":"eyJHcm","SymCtxt":"+yHR","Nonce":"kgjHyT3Jar0M155E"}`) - DecryptedSecrets []byte = []byte(`{"0x0":"lhcK"}`) - SignedCBORRequestHex = "a666736f75726365782172657475726e2046756e6374696f6e732e656e636f646555696e743235362831296773656372657473421234686c616e6775616765006c636f64654c6f636174696f6e006f736563726574734c6f636174696f6e0170726571756573745369676e617475726558416fb6d10871aa3865b6620dc5f4594d2a9ad9166ba6b1dbc3f508362fd27aa0461babada48979092a11ecadec9c663a2ea99da4e368408b36a3fb414acfefdd2a1c" - SubOwnerAddr common.Address = common.HexToAddress("0x2334dE553AB93c69b0ccbe278B6f5E8350Db6204") - NonSubOwnerAddr common.Address = common.HexToAddress("0x60C9CF55b9de9A956d921A97575108149b758131") + RequestID = newRequestID() + RequestIDStr = fmt.Sprintf("0x%x", [32]byte(RequestID)) + SubscriptionOwner = common.BigToAddress(big.NewInt(42069)) + SubscriptionID = uint64(5) + ResultBytes = []byte{0xab, 0xcd} + ErrorBytes = []byte{0xff, 0x11} + Domains = []string{"github.com", "google.com"} + EncryptedSecretsUrls = []byte{0x11, 0x22} + EncryptedSecrets = []byte(`{"TDH2Ctxt":"eyJHcm","SymCtxt":"+yHR","Nonce":"kgjHyT3Jar0M155E"}`) + DecryptedSecrets = []byte(`{"0x0":"lhcK"}`) + SignedCBORRequestHex = "a666736f75726365782172657475726e2046756e6374696f6e732e656e636f646555696e743235362831296773656372657473421234686c616e6775616765006c636f64654c6f636174696f6e006f736563726574734c6f636174696f6e0170726571756573745369676e617475726558416fb6d10871aa3865b6620dc5f4594d2a9ad9166ba6b1dbc3f508362fd27aa0461babada48979092a11ecadec9c663a2ea99da4e368408b36a3fb414acfefdd2a1c" + SubOwnerAddr = common.HexToAddress("0x2334dE553AB93c69b0ccbe278B6f5E8350Db6204") + NonSubOwnerAddr = common.HexToAddress("0x60C9CF55b9de9A956d921A97575108149b758131") ) -func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySec int, setTiers bool, version uint32) *FunctionsListenerUniverse { +func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySec int) *FunctionsListenerUniverse { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) @@ -105,13 +100,11 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe "decryptionQueueConfig": map[string]interface{}{ "decryptRequestTimeoutSec": 100, }, - "contractVersion": version, - "listenerEventsCheckFrequencyMillis": 100, // only applicable to v1 - } - if setTiers { - jsonConfig["maxRequestSizesList"] = []uint32{10, 100, 1_000} - jsonConfig["maxSecretsSizesList"] = []uint32{10, 100, 200} + "contractVersion": 1, + "listenerEventsCheckFrequencyMillis": 100, } + jsonConfig["maxRequestSizesList"] = []uint32{10, 100, 1_000} + jsonConfig["maxSecretsSizesList"] = []uint32{10, 100, 200} jb := job.Job{ Type: job.OffchainReporting2, SchemaVersion: 1, @@ -130,103 +123,92 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe contractAddress := "0xa" - ingressClient := sync_mocks.NewTelemetryIngressClient(t) + ingressClient := sync_mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monEndpoint := ingressAgent.GenMonitoringEndpoint(contractAddress, synchronization.FunctionsRequests) + monEndpoint := ingressAgent.GenMonitoringEndpoint(contractAddress, synchronization.FunctionsRequests, "test-network", "test-chainID") s4Storage := s4_mocks.NewStorage(t) client := chain.Client() logPollerWrapper := evmrelay_mocks.NewLogPollerWrapper(t) - functionsListener := functions_service.NewFunctionsListener(jb, client, contractAddress, bridgeAccessor, pluginORM, pluginConfig, s4Storage, broadcaster, lggr, mailMon, monEndpoint, decryptor, logPollerWrapper) + functionsListener := functions_service.NewFunctionsListener(jb, client, contractAddress, bridgeAccessor, pluginORM, pluginConfig, s4Storage, lggr, monEndpoint, decryptor, logPollerWrapper) return &FunctionsListenerUniverse{ service: functionsListener, bridgeAccessor: bridgeAccessor, eaClient: eaClient, pluginORM: pluginORM, - logBroadcaster: broadcaster, ingressClient: ingressClient, decryptor: decryptor, logPollerWrapper: logPollerWrapper, - contractVersion: pluginConfig.ContractVersion, } } -func PrepareAndStartFunctionsListener(t *testing.T, cbor []byte) (*FunctionsListenerUniverse, *log_mocks.Broadcast, chan struct{}) { - uni := NewFunctionsListenerUniverse(t, 0, 1_000_000, false, 0) - uni.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - - err := uni.service.Start(testutils.Context(t)) - require.NoError(t, err) - - log := log_mocks.NewBroadcast(t) - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := ocr2dr_oracle.OCR2DROracleOracleRequest{ - RequestId: RequestID, - RequestingContract: common.Address{}, - RequestInitiator: common.Address{}, - SubscriptionId: uint64(SubscriptionID), - SubscriptionOwner: SubscriptionOwner, - Data: cbor, - } - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - return uni, log, make(chan struct{}) +func packFlags(requestSizeTier int, secretSizeTier int) [32]byte { + var flags [32]byte + flags[1] = byte(requestSizeTier) + flags[2] = byte(secretSizeTier) + return flags } -func TestFunctionsListener_HandleOracleRequestSuccess(t *testing.T) { +func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - uni, log, doneCh := PrepareAndStartFunctionsListener(t, []byte{}) + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + doneCh := make(chan struct{}) + + request := types.OracleRequest{ + RequestId: RequestID, + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner, + Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes + Data: make([]byte, 12), + } + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, nil, nil) uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(doneCh) }).Return(nil) - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } -func TestFunctionsListener_ThresholdDecryptedSecrets(t *testing.T) { +func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - reqData := &struct { - SecretsLocation int `cbor:"secretsLocation"` - Secrets []byte `cbor:"secrets"` - }{ - SecretsLocation: 1, - Secrets: EncryptedSecretsUrls, - } - cborBytes, err := cbor.Marshal(reqData) - require.NoError(t, err) - // Remove first byte (map header) to make it "diet" CBOR - cborBytes = cborBytes[1:] + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + doneCh := make(chan struct{}) - uni, log, doneCh := PrepareAndStartFunctionsListener(t, cborBytes) + request := types.OracleRequest{ + RequestId: RequestID, + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner, + Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes + Data: make([]byte, 12), + } + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) - uni.eaClient.On("FetchEncryptedSecrets", mock.Anything, mock.Anything, RequestIDStr, mock.Anything, mock.Anything).Return(EncryptedSecrets, nil, nil) - uni.decryptor.On("Decrypt", mock.Anything, decryptionPlugin.CiphertextId(RequestID[:]), EncryptedSecrets).Return(DecryptedSecrets, nil) - uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, string(DecryptedSecrets), mock.Anything).Return(ResultBytes, nil, nil, nil) - uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrorBytes, nil, nil) + uni.pluginORM.On("SetError", RequestID, mock.Anything, ErrorBytes, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(doneCh) }).Return(nil) - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } -func TestFunctionsListener_ThresholdDecryptedSecretsFailure(t *testing.T) { +func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() @@ -241,35 +223,56 @@ func TestFunctionsListener_ThresholdDecryptedSecretsFailure(t *testing.T) { require.NoError(t, err) // Remove first byte (map header) to make it "diet" CBOR cborBytes = cborBytes[1:] + request := types.OracleRequest{ + RequestId: RequestID, + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner, + Flags: packFlags(1, 1), // tiers no 1 of request size and secrets size, allow up to 100 bytes + Data: cborBytes, + } - uni, log, doneCh := PrepareAndStartFunctionsListener(t, cborBytes) + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + doneCh := make(chan struct{}) + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) uni.eaClient.On("FetchEncryptedSecrets", mock.Anything, mock.Anything, RequestIDStr, mock.Anything, mock.Anything).Return(EncryptedSecrets, nil, nil) - uni.decryptor.On("Decrypt", mock.Anything, decryptionPlugin.CiphertextId(RequestID[:]), EncryptedSecrets).Return(nil, errors.New("threshold decryption error")) - uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, []byte("threshold decryption of secrets failed"), mock.Anything, true, mock.Anything).Run(func(args mock.Arguments) { + uni.decryptor.On("Decrypt", mock.Anything, decryptionPlugin.CiphertextId(RequestID[:]), EncryptedSecrets).Return(DecryptedSecrets, nil) + uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, nil, nil) + uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(doneCh) }).Return(nil) - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } -func TestFunctionsListener_HandleOracleRequestDuplicateMarkLogConsumed(t *testing.T) { +func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - uni, log, doneCh := PrepareAndStartFunctionsListener(t, []byte{}) + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + doneCh := make(chan struct{}) + + request := types.OracleRequest{ + RequestId: RequestID, + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner, + Flags: packFlags(0, 0), // tier no 0 of request size, allows only for max 10 bytes + Data: make([]byte, 20), + } - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(functions_service.ErrDuplicateRequestID) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) + uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) + uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, []byte("request too big (max 10 bytes)"), mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(doneCh) }).Return(nil) - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } @@ -278,27 +281,35 @@ func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - uni, log, doneCh := PrepareAndStartFunctionsListener(t, []byte{}) + uni := NewFunctionsListenerUniverse(t, 0, 1_000_000) + doneCh := make(chan struct{}) + + request := types.OracleRequest{ + RequestId: RequestID, + SubscriptionId: uint64(SubscriptionID), + SubscriptionOwner: SubscriptionOwner, + Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes + Data: make([]byte, 12), + } + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, Domains, nil) uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { close(doneCh) }).Return(nil) - var sentMessage []byte - uni.ingressClient.On("Send", mock.Anything).Return().Run(func(args mock.Arguments) { - sentMessage = args[0].(synchronization.TelemPayload).Telemetry + uni.ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + sentMessage = args[1].([]byte) }) - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() assert.NotEmpty(t, sentMessage) - var req telem.FunctionsRequest err := proto.Unmarshal(sentMessage, &req) assert.NoError(t, err) @@ -306,128 +317,34 @@ func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { assert.EqualValues(t, Domains, req.Domains) } -func TestFunctionsListener_HandleOracleRequestComputationError(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - uni, log, doneCh := PrepareAndStartFunctionsListener(t, []byte{}) - - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) - uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) - uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrorBytes, nil, nil) - uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, ErrorBytes, mock.Anything, true, mock.Anything).Run(func(args mock.Arguments) { - close(doneCh) - }).Return(nil) - - uni.service.HandleLog(log) - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_HandleOracleRequestCBORParsingError(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - uni, log, doneCh := PrepareAndStartFunctionsListener(t, []byte("invalid cbor")) - - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) - uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, []byte("CBOR parsing error"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - close(doneCh) - }) - - uni.service.HandleLog(log) - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_HandleOracleRequestCBORParsingErrorInvalidFieldType(t *testing.T) { +func TestFunctionsListener_PruneRequests(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - incomingData := &struct { - Source string `cbor:"source"` - CodeLocation string `cbor:"codeLocation"` // incorrect type - }{ - Source: "abcd", - CodeLocation: "inline", - } - cborBytes, err := cbor.Marshal(incomingData) - require.NoError(t, err) - // Remove first byte (map header) to make it "diet" CBOR - cborBytes = cborBytes[1:] - uni, log, doneCh := PrepareAndStartFunctionsListener(t, cborBytes) - - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) - uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, []byte("CBOR parsing error"), mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) { - close(doneCh) + uni := NewFunctionsListenerUniverse(t, 0, 1) + doneCh := make(chan bool) + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) + uni.pluginORM.On("PruneOldestRequests", functions_service.DefaultPruneMaxStoredRequests, functions_service.DefaultPruneBatchSize, mock.Anything).Return(uint32(0), uint32(0), nil).Run(func(args mock.Arguments) { + doneCh <- true }) - uni.service.HandleLog(log) - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_HandleOracleRequestCBORParsingCorrect(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - incomingData := &struct { - Source string `cbor:"source"` - Language int `cbor:"language"` - Secrets []byte `cbor:"secrets"` - Args []string `cbor:"args"` - ExtraUnwantedParam string `cbor:"extraUnwantedParam"` - // missing CodeLocation and SecretsLocation - }{ - Source: "abcd", - Language: 3, - Secrets: []byte{0xaa, 0xbb}, - Args: []string{"a", "b"}, - ExtraUnwantedParam: "spam", - } - cborBytes, err := cbor.Marshal(incomingData) - require.NoError(t, err) - // Remove first byte (map header) to make it "diet" CBOR - cborBytes = cborBytes[1:] - - uni, log, doneCh := PrepareAndStartFunctionsListener(t, cborBytes) - - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything).Return(nil) - uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) - uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - reqData := args.Get(7).(*functions_service.RequestData) - assert.Equal(t, incomingData.Source, reqData.Source) - assert.Equal(t, incomingData.Language, reqData.Language) - assert.Equal(t, incomingData.Secrets, reqData.Secrets) - assert.Equal(t, incomingData.Args, reqData.Args) - }).Return(ResultBytes, nil, nil, nil) - uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - close(doneCh) - }).Return(nil) - - uni.service.HandleLog(log) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } -func TestFunctionsListener_RequestTimeout(t *testing.T) { +func TestFunctionsListener_TimeoutRequests(t *testing.T) { testutils.SkipShortDB(t) t.Parallel() - reqId := newRequestID() + uni := NewFunctionsListenerUniverse(t, 1, 0) doneCh := make(chan bool) - uni := NewFunctionsListenerUniverse(t, 1, 1_000_000, false, 0) - uni.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - uni.pluginORM.On("TimeoutExpiredResults", mock.Anything, uint32(1), mock.Anything).Return([]functions_service.RequestID{reqId}, nil).Run(func(args mock.Arguments) { + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) + uni.pluginORM.On("TimeoutExpiredResults", mock.Anything, uint32(1), mock.Anything).Return([]functions_service.RequestID{}, nil).Run(func(args mock.Arguments) { doneCh <- true }) - err := uni.service.Start(testutils.Context(t)) - require.NoError(t, err) + require.NoError(t, uni.service.Start(testutils.Context(t))) <-doneCh uni.service.Close() } @@ -438,7 +355,11 @@ func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { var ormCallExited sync.WaitGroup ormCallExited.Add(1) - uni, log, _ := PrepareAndStartFunctionsListener(t, []byte{}) + uni := NewFunctionsListenerUniverse(t, 0, 0) + request := types.OracleRequest{} + + uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() + uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { var queryerWrapper pg.Q args.Get(1).(pg.QOpt)(&queryerWrapper) @@ -446,160 +367,7 @@ func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { ormCallExited.Done() }).Return(errors.New("timeout")) - uni.service.HandleLog(log) - - ormCallExited.Wait() // should not freeze - uni.service.Close() -} - -func TestFunctionsListener_PruneRequests(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - doneCh := make(chan bool) - uni := NewFunctionsListenerUniverse(t, 0, 1, false, 0) - uni.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - uni.pluginORM.On("PruneOldestRequests", functions_service.DefaultPruneMaxStoredRequests, functions_service.DefaultPruneBatchSize, mock.Anything).Return(uint32(0), uint32(0), nil).Run(func(args mock.Arguments) { - doneCh <- true - }) - - err := uni.service.Start(testutils.Context(t)) - require.NoError(t, err) - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_RequestSignatureVerification(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - cborBytes, err := hex.DecodeString(SignedCBORRequestHex) - require.NoError(t, err) - - var requestData functions_service.RequestData - err = cl_cbor.ParseDietCBORToStruct(cborBytes, &requestData) - require.NoError(t, err) - - err = functions_service.VerifyRequestSignature(SubOwnerAddr, &requestData) - assert.NoError(t, err) -} - -func TestFunctionsListener_RequestSignatureVerificationFailure(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - cborBytes, err := hex.DecodeString(SignedCBORRequestHex) - require.NoError(t, err) - - var requestData functions_service.RequestData - err = cl_cbor.ParseDietCBORToStruct(cborBytes, &requestData) - require.NoError(t, err) - - err = functions_service.VerifyRequestSignature(NonSubOwnerAddr, &requestData) - assert.EqualError(t, err, "invalid request signature: signer's address does not match subscription owner") -} - -func getFlags(requestSizeTier int, secretSizeTier int) [32]byte { - var flags [32]byte - flags[1] = byte(requestSizeTier) - flags[2] = byte(secretSizeTier) - return flags -} - -func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - uni := NewFunctionsListenerUniverse(t, 0, 1_000_000, true, 1) require.NoError(t, uni.service.Start(testutils.Context(t))) - doneCh := make(chan struct{}) - - request := types.OracleRequest{ - RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), - SubscriptionOwner: SubscriptionOwner, - Flags: getFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes - Data: make([]byte, 12), - } - - uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() - uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) - uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, nil, nil) - uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - close(doneCh) - }).Return(nil) - - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - reqData := &struct { - SecretsLocation int `cbor:"secretsLocation"` - Secrets []byte `cbor:"secrets"` - }{ - SecretsLocation: 1, - Secrets: EncryptedSecretsUrls, - } - cborBytes, err := cbor.Marshal(reqData) - require.NoError(t, err) - // Remove first byte (map header) to make it "diet" CBOR - cborBytes = cborBytes[1:] - request := types.OracleRequest{ - RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), - SubscriptionOwner: SubscriptionOwner, - Flags: getFlags(1, 1), // tiers no 1 of request size and secrets size, allow up to 100 bytes - Data: cborBytes, - } - - uni := NewFunctionsListenerUniverse(t, 0, 1_000_000, true, 1) - require.NoError(t, uni.service.Start(testutils.Context(t))) - doneCh := make(chan struct{}) - - uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() - uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.bridgeAccessor.On("NewExternalAdapterClient").Return(uni.eaClient, nil) - uni.eaClient.On("FetchEncryptedSecrets", mock.Anything, mock.Anything, RequestIDStr, mock.Anything, mock.Anything).Return(EncryptedSecrets, nil, nil) - uni.decryptor.On("Decrypt", mock.Anything, decryptionPlugin.CiphertextId(RequestID[:]), EncryptedSecrets).Return(DecryptedSecrets, nil) - uni.eaClient.On("RunComputation", mock.Anything, RequestIDStr, mock.Anything, SubscriptionOwner.Hex(), SubscriptionID, mock.Anything, mock.Anything, mock.Anything).Return(ResultBytes, nil, nil, nil) - uni.pluginORM.On("SetResult", RequestID, ResultBytes, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - close(doneCh) - }).Return(nil) - - <-doneCh - uni.service.Close() -} - -func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { - testutils.SkipShortDB(t) - t.Parallel() - - uni := NewFunctionsListenerUniverse(t, 0, 1_000_000, true, 1) - require.NoError(t, uni.service.Start(testutils.Context(t))) - doneCh := make(chan struct{}) - - request := types.OracleRequest{ - RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), - SubscriptionOwner: SubscriptionOwner, - Flags: getFlags(0, 0), // tier no 0 of request size, allows only for max 10 bytes - Data: make([]byte, 20), - } - - uni.logPollerWrapper.On("LatestEvents").Return([]types.OracleRequest{request}, nil, nil).Once() - uni.logPollerWrapper.On("LatestEvents").Return(nil, nil, nil) - uni.pluginORM.On("CreateRequest", mock.Anything, mock.Anything).Return(nil) - uni.pluginORM.On("SetError", RequestID, functions_service.USER_ERROR, []byte("request too big (max 10 bytes)"), mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - close(doneCh) - }).Return(nil) - - <-doneCh + ormCallExited.Wait() // should not freeze uni.service.Close() } diff --git a/core/services/functions/mocks/bridge_accessor.go b/core/services/functions/mocks/bridge_accessor.go index 291def633e3..65e81ab8b83 100644 --- a/core/services/functions/mocks/bridge_accessor.go +++ b/core/services/functions/mocks/bridge_accessor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -38,13 +38,12 @@ func (_m *BridgeAccessor) NewExternalAdapterClient() (functions.ExternalAdapterC return r0, r1 } -type mockConstructorTestingTNewBridgeAccessor interface { +// NewBridgeAccessor creates a new instance of BridgeAccessor. 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 NewBridgeAccessor(t interface { mock.TestingT Cleanup(func()) -} - -// NewBridgeAccessor creates a new instance of BridgeAccessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewBridgeAccessor(t mockConstructorTestingTNewBridgeAccessor) *BridgeAccessor { +}) *BridgeAccessor { mock := &BridgeAccessor{} mock.Mock.Test(t) diff --git a/core/services/functions/mocks/external_adapter_client.go b/core/services/functions/mocks/external_adapter_client.go index 2815819251b..b06f13fdea7 100644 --- a/core/services/functions/mocks/external_adapter_client.go +++ b/core/services/functions/mocks/external_adapter_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -93,13 +93,12 @@ func (_m *ExternalAdapterClient) RunComputation(ctx context.Context, requestId s return r0, r1, r2, r3 } -type mockConstructorTestingTNewExternalAdapterClient interface { +// NewExternalAdapterClient creates a new instance of ExternalAdapterClient. 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 NewExternalAdapterClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewExternalAdapterClient creates a new instance of ExternalAdapterClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewExternalAdapterClient(t mockConstructorTestingTNewExternalAdapterClient) *ExternalAdapterClient { +}) *ExternalAdapterClient { mock := &ExternalAdapterClient{} mock.Mock.Test(t) diff --git a/core/services/functions/mocks/orm.go b/core/services/functions/mocks/orm.go index 3850ccdb67a..8d11b0b9817 100644 --- a/core/services/functions/mocks/orm.go +++ b/core/services/functions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -258,13 +258,12 @@ func (_m *ORM) TimeoutExpiredResults(cutoff time.Time, limit uint32, qopts ...pg return r0, r1 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/functions/request.go b/core/services/functions/request.go index a6715e0a87f..181058b83d0 100644 --- a/core/services/functions/request.go +++ b/core/services/functions/request.go @@ -1,14 +1,5 @@ package functions -import ( - "encoding/json" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - const ( LocationInline = 0 LocationRemote = 1 @@ -19,14 +10,13 @@ const ( type RequestFlags [32]byte type RequestData struct { - Source string `json:"source" cbor:"source"` - Language int `json:"language" cbor:"language"` - CodeLocation int `json:"codeLocation" cbor:"codeLocation"` - Secrets []byte `json:"secrets" cbor:"secrets"` - SecretsLocation int `json:"secretsLocation" cbor:"secretsLocation"` - RequestSignature []byte `json:"requestSignature,omitempty" cbor:"requestSignature"` - Args []string `json:"args,omitempty" cbor:"args"` - BytesArgs [][]byte `json:"bytesArgs,omitempty" cbor:"bytesArgs"` + Source string `json:"source" cbor:"source"` + Language int `json:"language" cbor:"language"` + CodeLocation int `json:"codeLocation" cbor:"codeLocation"` + Secrets []byte `json:"secrets,omitempty" cbor:"secrets"` + SecretsLocation int `json:"secretsLocation" cbor:"secretsLocation"` + Args []string `json:"args,omitempty" cbor:"args"` + BytesArgs [][]byte `json:"bytesArgs,omitempty" cbor:"bytesArgs"` } type DONHostedSecrets struct { @@ -41,41 +31,3 @@ type SignedRequestData struct { SecretsLocation int `json:"secretsLocation" cbor:"secretsLocation"` Source string `json:"source" cbor:"source"` } - -// The request signature should sign the keccak256 hash of the following JSON string (without extra whitespace) -// with the corresponding Request fields in the order that they appear below: -// { -// "codeLocation": number, (0 for Location.Inline) -// "language": number, (0 for CodeLanguage.JavaScript) -// "secrets": string, (encryptedSecretsReference as base64 string, must be `null` if there are no secrets) -// "secretsLocation": number, (must be `null` if there are no secrets) (1 for Location.Remote, 2 for Location.DONHosted) -// "source": string, -// } - -func VerifyRequestSignature(subscriptionOwner common.Address, requestData *RequestData) error { - if requestData.RequestSignature == nil { - return errors.New("missing signature") - } - signedRequestData := SignedRequestData{ - CodeLocation: requestData.CodeLocation, - Language: requestData.Language, - Secrets: requestData.Secrets, - SecretsLocation: requestData.SecretsLocation, - Source: requestData.Source, - } - js, err := json.Marshal(signedRequestData) - if err != nil { - return errors.New("unable to marshal request data") - } - - signerAddr, err := utils.GetSignersEthAddress(js, requestData.RequestSignature) - if err != nil { - return errors.New("invalid request signature: unable to recover signer's address") - } - - if signerAddr != subscriptionOwner { - return errors.New("invalid request signature: signer's address does not match subscription owner") - } - - return nil -} diff --git a/core/services/gateway/common/utils.go b/core/services/gateway/common/utils.go index 2e5033432bb..59c67bdcfa1 100644 --- a/core/services/gateway/common/utils.go +++ b/core/services/gateway/common/utils.go @@ -3,8 +3,7 @@ package common import ( "crypto/ecdsa" "encoding/binary" - - "golang.org/x/exp/slices" + "slices" "github.com/smartcontractkit/chainlink/v2/core/utils" ) diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index f225b66fe18..ae2ade6511e 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -14,7 +14,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" - "golang.org/x/exp/maps" + + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" @@ -57,7 +58,7 @@ func (m *connectionManager) HealthReport() map[string]error { hr := map[string]error{m.Name(): m.Healthy()} for _, d := range m.dons { for _, n := range d.nodes { - maps.Copy(hr, n.conn.HealthReport()) + services.CopyHealth(hr, n.conn.HealthReport()) } } return hr diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 4cc84d37490..dd8dce473b5 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "golang.org/x/exp/maps" - "github.com/gorilla/websocket" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/network" @@ -64,7 +64,7 @@ type gatewayConnector struct { func (c *gatewayConnector) HealthReport() map[string]error { m := map[string]error{c.Name(): c.Healthy()} for _, g := range c.gateways { - maps.Copy(m, g.conn.HealthReport()) + services.CopyHealth(m, g.conn.HealthReport()) } return m } diff --git a/core/services/gateway/connector/mocks/gateway_connector.go b/core/services/gateway/connector/mocks/gateway_connector.go index 7a581fb6260..a9fa69e1e3b 100644 --- a/core/services/gateway/connector/mocks/gateway_connector.go +++ b/core/services/gateway/connector/mocks/gateway_connector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -111,13 +111,12 @@ func (_m *GatewayConnector) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewGatewayConnector interface { +// NewGatewayConnector creates a new instance of GatewayConnector. 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 NewGatewayConnector(t interface { mock.TestingT Cleanup(func()) -} - -// NewGatewayConnector creates a new instance of GatewayConnector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewGatewayConnector(t mockConstructorTestingTNewGatewayConnector) *GatewayConnector { +}) *GatewayConnector { mock := &GatewayConnector{} mock.Mock.Test(t) diff --git a/core/services/gateway/connector/mocks/gateway_connector_handler.go b/core/services/gateway/connector/mocks/gateway_connector_handler.go index 1db0f45fa12..8eb27708a5a 100644 --- a/core/services/gateway/connector/mocks/gateway_connector_handler.go +++ b/core/services/gateway/connector/mocks/gateway_connector_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -48,13 +48,12 @@ func (_m *GatewayConnectorHandler) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewGatewayConnectorHandler interface { +// NewGatewayConnectorHandler creates a new instance of GatewayConnectorHandler. 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 NewGatewayConnectorHandler(t interface { mock.TestingT Cleanup(func()) -} - -// NewGatewayConnectorHandler creates a new instance of GatewayConnectorHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewGatewayConnectorHandler(t mockConstructorTestingTNewGatewayConnectorHandler) *GatewayConnectorHandler { +}) *GatewayConnectorHandler { mock := &GatewayConnectorHandler{} mock.Mock.Test(t) diff --git a/core/services/gateway/connector/mocks/signer.go b/core/services/gateway/connector/mocks/signer.go index 946f2d47b78..497b25d8df3 100644 --- a/core/services/gateway/connector/mocks/signer.go +++ b/core/services/gateway/connector/mocks/signer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -41,13 +41,12 @@ func (_m *Signer) Sign(data ...[]byte) ([]byte, error) { return r0, r1 } -type mockConstructorTestingTNewSigner interface { +// NewSigner creates a new instance of Signer. 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 NewSigner(t interface { mock.TestingT Cleanup(func()) -} - -// NewSigner creates a new instance of Signer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSigner(t mockConstructorTestingTNewSigner) *Signer { +}) *Signer { mock := &Signer{} mock.Mock.Test(t) diff --git a/core/services/gateway/delegate.go b/core/services/gateway/delegate.go index c42e61b8785..909ca21ad73 100644 --- a/core/services/gateway/delegate.go +++ b/core/services/gateway/delegate.go @@ -37,7 +37,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the scheduler to be used for running observer jobs -func (d *Delegate) ServicesForSpec(spec job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { if spec.GatewaySpec == nil { return nil, errors.Errorf("services.Delegate expects a *jobSpec.GatewaySpec to be present, got %v", spec) } diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist.go index 0ee9b5bcfb9..d3619d9071e 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist.go @@ -16,7 +16,6 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_allow_list" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_oracle" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -51,7 +50,6 @@ type onchainAllowlist struct { config OnchainAllowlistConfig allowlist atomic.Pointer[map[common.Address]struct{}] client evmclient.Client - contractV0 *ocr2dr_oracle.OCR2DROracle contractV1 *functions_router.FunctionsRouter blockConfirmations *big.Int lggr logger.Logger @@ -66,9 +64,8 @@ func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, if lggr == nil { return nil, errors.New("logger is nil") } - contractV0, err := ocr2dr_oracle.NewOCR2DROracle(config.ContractAddress, client) - if err != nil { - return nil, fmt.Errorf("unexpected error during NewOCR2DROracle: %s", err) + if config.ContractVersion != 1 { + return nil, fmt.Errorf("unsupported contract version %d", config.ContractVersion) } contractV1, err := functions_router.NewFunctionsRouter(config.ContractAddress, client) if err != nil { @@ -77,7 +74,6 @@ func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, allowlist := &onchainAllowlist{ config: config, client: client, - contractV0: contractV0, contractV1: contractV1, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), lggr: lggr.Named("OnchainAllowlist"), @@ -148,26 +144,7 @@ func (a *onchainAllowlist) UpdateFromContract(ctx context.Context) error { return errors.New("LatestBlockHeight returned nil") } blockNum := big.NewInt(0).Sub(latestBlockHeight, a.blockConfirmations) - if a.config.ContractVersion == 0 { - return a.updateFromContractV0(ctx, blockNum) - } else if a.config.ContractVersion == 1 { - return a.updateFromContractV1(ctx, blockNum) - } else { - return fmt.Errorf("unknown contract version %d", a.config.ContractVersion) - } -} - -func (a *onchainAllowlist) updateFromContractV0(ctx context.Context, blockNum *big.Int) error { - addrList, err := a.contractV0.GetAuthorizedSenders(&bind.CallOpts{ - Pending: false, - BlockNumber: blockNum, - Context: ctx, - }) - if err != nil { - return errors.Wrap(err, "error calling GetAuthorizedSenders") - } - a.update(addrList) - return nil + return a.updateFromContractV1(ctx, blockNum) } func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *big.Int) error { diff --git a/core/services/gateway/handlers/functions/allowlist_test.go b/core/services/gateway/handlers/functions/allowlist_test.go index 9ec6ef30457..fdaea81b2c0 100644 --- a/core/services/gateway/handlers/functions/allowlist_test.go +++ b/core/services/gateway/handlers/functions/allowlist_test.go @@ -39,31 +39,41 @@ func sampleEncodedAllowlist(t *testing.T) []byte { func TestAllowlist_UpdateAndCheck(t *testing.T) { t.Parallel() - for _, version := range []uint32{0, 1} { - client := mocks.NewClient(t) - client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) - // both contract versions have the same return type - client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(sampleEncodedAllowlist(t), nil) - config := functions.OnchainAllowlistConfig{ - ContractVersion: version, - ContractAddress: common.Address{}, - BlockConfirmations: 1, - } - allowlist, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) - require.NoError(t, err) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(sampleEncodedAllowlist(t), nil) + config := functions.OnchainAllowlistConfig{ + ContractVersion: 1, + ContractAddress: common.Address{}, + BlockConfirmations: 1, + } + allowlist, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.Start(testutils.Context(t)) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, allowlist.Close()) + }) + + require.NoError(t, allowlist.UpdateFromContract(testutils.Context(t))) + require.False(t, allowlist.Allow(common.Address{})) + require.True(t, allowlist.Allow(common.HexToAddress(addr1))) + require.True(t, allowlist.Allow(common.HexToAddress(addr2))) + require.False(t, allowlist.Allow(common.HexToAddress(addr3))) +} - err = allowlist.Start(testutils.Context(t)) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, allowlist.Close()) - }) +func TestAllowlist_UnsupportedVersion(t *testing.T) { + t.Parallel() - require.NoError(t, allowlist.UpdateFromContract(testutils.Context(t))) - require.False(t, allowlist.Allow(common.Address{})) - require.True(t, allowlist.Allow(common.HexToAddress(addr1))) - require.True(t, allowlist.Allow(common.HexToAddress(addr2))) - require.False(t, allowlist.Allow(common.HexToAddress(addr3))) + client := mocks.NewClient(t) + config := functions.OnchainAllowlistConfig{ + ContractVersion: 0, + ContractAddress: common.Address{}, + BlockConfirmations: 1, } + _, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) + require.Error(t, err) } func TestAllowlist_UpdatePeriodically(t *testing.T) { @@ -77,7 +87,7 @@ func TestAllowlist_UpdatePeriodically(t *testing.T) { }).Return(sampleEncodedAllowlist(t), nil) config := functions.OnchainAllowlistConfig{ ContractAddress: common.Address{}, - ContractVersion: 0, + ContractVersion: 1, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, diff --git a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go index bc2303720f5..8cbf301f0ea 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go +++ b/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -71,13 +71,12 @@ func (_m *OnchainAllowlist) UpdateFromContract(ctx context.Context) error { return r0 } -type mockConstructorTestingTNewOnchainAllowlist interface { +// NewOnchainAllowlist creates a new instance of OnchainAllowlist. 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 NewOnchainAllowlist(t interface { mock.TestingT Cleanup(func()) -} - -// NewOnchainAllowlist creates a new instance of OnchainAllowlist. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOnchainAllowlist(t mockConstructorTestingTNewOnchainAllowlist) *OnchainAllowlist { +}) *OnchainAllowlist { mock := &OnchainAllowlist{} mock.Mock.Test(t) diff --git a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go index 86397407466..64e2960f949 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go +++ b/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -70,13 +70,12 @@ func (_m *OnchainSubscriptions) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewOnchainSubscriptions interface { +// NewOnchainSubscriptions creates a new instance of OnchainSubscriptions. 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 NewOnchainSubscriptions(t interface { mock.TestingT Cleanup(func()) -} - -// NewOnchainSubscriptions creates a new instance of OnchainSubscriptions. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOnchainSubscriptions(t mockConstructorTestingTNewOnchainSubscriptions) *OnchainSubscriptions { +}) *OnchainSubscriptions { mock := &OnchainSubscriptions{} mock.Mock.Test(t) diff --git a/core/services/gateway/handlers/mocks/don.go b/core/services/gateway/handlers/mocks/don.go index 769056357f6..02df7c0334f 100644 --- a/core/services/gateway/handlers/mocks/don.go +++ b/core/services/gateway/handlers/mocks/don.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -29,13 +29,12 @@ func (_m *DON) SendToNode(ctx context.Context, nodeAddress string, msg *api.Mess return r0 } -type mockConstructorTestingTNewDON interface { +// NewDON creates a new instance of DON. 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 NewDON(t interface { mock.TestingT Cleanup(func()) -} - -// NewDON creates a new instance of DON. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDON(t mockConstructorTestingTNewDON) *DON { +}) *DON { mock := &DON{} mock.Mock.Test(t) diff --git a/core/services/gateway/handlers/mocks/handler.go b/core/services/gateway/handlers/mocks/handler.go index 4348150207a..10a31c6d76e 100644 --- a/core/services/gateway/handlers/mocks/handler.go +++ b/core/services/gateway/handlers/mocks/handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -73,13 +73,12 @@ func (_m *Handler) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewHandler interface { +// NewHandler creates a new instance of Handler. 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 NewHandler(t interface { mock.TestingT Cleanup(func()) -} - -// NewHandler creates a new instance of Handler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHandler(t mockConstructorTestingTNewHandler) *Handler { +}) *Handler { mock := &Handler{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/mocks/connection_acceptor.go b/core/services/gateway/network/mocks/connection_acceptor.go index 6786ad7fb59..738904984af 100644 --- a/core/services/gateway/network/mocks/connection_acceptor.go +++ b/core/services/gateway/network/mocks/connection_acceptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -65,13 +65,12 @@ func (_m *ConnectionAcceptor) StartHandshake(authHeader []byte) (string, []byte, return r0, r1, r2 } -type mockConstructorTestingTNewConnectionAcceptor interface { +// NewConnectionAcceptor creates a new instance of ConnectionAcceptor. 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 NewConnectionAcceptor(t interface { mock.TestingT Cleanup(func()) -} - -// NewConnectionAcceptor creates a new instance of ConnectionAcceptor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConnectionAcceptor(t mockConstructorTestingTNewConnectionAcceptor) *ConnectionAcceptor { +}) *ConnectionAcceptor { mock := &ConnectionAcceptor{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/mocks/connection_initiator.go b/core/services/gateway/network/mocks/connection_initiator.go index a3e09b3afc8..3ff60e61398 100644 --- a/core/services/gateway/network/mocks/connection_initiator.go +++ b/core/services/gateway/network/mocks/connection_initiator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -65,13 +65,12 @@ func (_m *ConnectionInitiator) NewAuthHeader(_a0 *url.URL) ([]byte, error) { return r0, r1 } -type mockConstructorTestingTNewConnectionInitiator interface { +// NewConnectionInitiator creates a new instance of ConnectionInitiator. 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 NewConnectionInitiator(t interface { mock.TestingT Cleanup(func()) -} - -// NewConnectionInitiator creates a new instance of ConnectionInitiator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConnectionInitiator(t mockConstructorTestingTNewConnectionInitiator) *ConnectionInitiator { +}) *ConnectionInitiator { mock := &ConnectionInitiator{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/mocks/http_request_handler.go b/core/services/gateway/network/mocks/http_request_handler.go index f25a5476c44..7716626ac72 100644 --- a/core/services/gateway/network/mocks/http_request_handler.go +++ b/core/services/gateway/network/mocks/http_request_handler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -39,13 +39,12 @@ func (_m *HTTPRequestHandler) ProcessRequest(ctx context.Context, rawRequest []b return r0, r1 } -type mockConstructorTestingTNewHTTPRequestHandler interface { +// NewHTTPRequestHandler creates a new instance of HTTPRequestHandler. 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 NewHTTPRequestHandler(t interface { mock.TestingT Cleanup(func()) -} - -// NewHTTPRequestHandler creates a new instance of HTTPRequestHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHTTPRequestHandler(t mockConstructorTestingTNewHTTPRequestHandler) *HTTPRequestHandler { +}) *HTTPRequestHandler { mock := &HTTPRequestHandler{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/mocks/http_server.go b/core/services/gateway/network/mocks/http_server.go index 1360a8ea1cf..197e77f1b8a 100644 --- a/core/services/gateway/network/mocks/http_server.go +++ b/core/services/gateway/network/mocks/http_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -61,13 +61,12 @@ func (_m *HttpServer) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewHttpServer interface { +// NewHttpServer creates a new instance of HttpServer. 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 NewHttpServer(t interface { mock.TestingT Cleanup(func()) -} - -// NewHttpServer creates a new instance of HttpServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHttpServer(t mockConstructorTestingTNewHttpServer) *HttpServer { +}) *HttpServer { mock := &HttpServer{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/mocks/web_socket_server.go b/core/services/gateway/network/mocks/web_socket_server.go index 4e109e2c7d1..d88cd5ba4f7 100644 --- a/core/services/gateway/network/mocks/web_socket_server.go +++ b/core/services/gateway/network/mocks/web_socket_server.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -55,13 +55,12 @@ func (_m *WebSocketServer) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewWebSocketServer interface { +// NewWebSocketServer creates a new instance of WebSocketServer. 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 NewWebSocketServer(t interface { mock.TestingT Cleanup(func()) -} - -// NewWebSocketServer creates a new instance of WebSocketServer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewWebSocketServer(t mockConstructorTestingTNewWebSocketServer) *WebSocketServer { +}) *WebSocketServer { mock := &WebSocketServer{} mock.Mock.Test(t) diff --git a/core/services/gateway/network/wsconnection.go b/core/services/gateway/network/wsconnection.go index b2aaf445d20..345d951ed4a 100644 --- a/core/services/gateway/network/wsconnection.go +++ b/core/services/gateway/network/wsconnection.go @@ -5,7 +5,7 @@ import ( "errors" "sync/atomic" - "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/gorilla/websocket" @@ -30,7 +30,7 @@ import ( // All methods are thread-safe. type WSConnectionWrapper interface { job.ServiceCtx - services.Checkable + services.HealthReporter // Update underlying connection object. Return a channel that gets an error on connection close. // Cannot be called after Close(). diff --git a/core/services/health.go b/core/services/health.go index 1912a49b75e..568823fa324 100644 --- a/core/services/health.go +++ b/core/services/health.go @@ -4,236 +4,34 @@ import ( "context" "fmt" "net/http" - "sync" "time" "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -//go:generate mockery --quiet --name Checker --output ./mocks/ --case=underscore -type ( - // Checker provides a service which can be probed for system health. - Checker interface { - // Register a service for health checks. - Register(service Checkable) error - // Unregister a service. - Unregister(name string) error - // IsReady returns the current readiness of the system. - // A system is considered ready if all checks are passing (no errors) - IsReady() (ready bool, errors map[string]error) - // IsHealthy returns the current health of the system. - // A system is considered healthy if all checks are passing (no errors) - IsHealthy() (healthy bool, errors map[string]error) - - Start() error - Close() error - } - - checker struct { - srvMutex sync.RWMutex - services map[string]Checkable - stateMutex sync.RWMutex - healthy map[string]error - ready map[string]error - - chStop chan struct{} - chDone chan struct{} - - utils.StartStopOnce - } - - Status string -) - -var _ Checker = (*checker)(nil) - -const ( - StatusPassing Status = "passing" - StatusFailing Status = "failing" + "github.com/smartcontractkit/chainlink-relay/pkg/services" - interval = 15 * time.Second -) - -var ( - healthStatus = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "health", - Help: "Health status by service", - }, - []string{"service_id"}, - ) - uptimeSeconds = promauto.NewCounter( - prometheus.CounterOpts{ - Name: "uptime_seconds", - Help: "Uptime of the application measured in seconds", - }, - ) - nodeVersion = promauto.NewCounterVec( - prometheus.CounterOpts{ - Name: "version", - Help: "Node version information", - }, - []string{"version", "commit"}, - ) + "github.com/smartcontractkit/chainlink/v2/core/logger" ) -func NewChecker() Checker { - c := &checker{ - services: make(map[string]Checkable, 10), - healthy: make(map[string]error, 10), - ready: make(map[string]error, 10), - chStop: make(chan struct{}), - chDone: make(chan struct{}), - } - - return c -} - -func (c *checker) Start() error { - return c.StartOnce("HealthCheck", func() error { - nodeVersion.WithLabelValues(static.Version, static.Sha).Inc() - - // update immediately - c.update() - - go c.run() - - return nil - }) -} - -func (c *checker) Close() error { - return c.StopOnce("HealthCheck", func() error { - close(c.chStop) - <-c.chDone - return nil - }) -} - -func (c *checker) run() { - defer close(c.chDone) - - ticker := time.NewTicker(interval) - - for { - select { - case <-ticker.C: - c.update() - case <-c.chStop: - return - } - } - -} - -func (c *checker) update() { - healthy := make(map[string]error) - ready := make(map[string]error) - - c.srvMutex.RLock() - // copy services into a new map to avoid lock contention while doing checks - services := make(map[string]Checkable, len(c.services)) - for name, s := range c.services { - services[name] = s - } - c.srvMutex.RUnlock() - - // now, do all the checks - for name, s := range services { - ready[name] = s.Ready() - hr := s.HealthReport() - for n, err := range hr { - healthy[n] = err - } - - } - - // we use a separate lock to avoid holding the lock over state while talking - // to services - c.stateMutex.Lock() - defer c.stateMutex.Unlock() - for name, r := range ready { - c.ready[name] = r - } - - for name, h := range healthy { - c.healthy[name] = h - - value := 0 - if h == nil { - value = 1 - } - - // report metrics to prometheus - healthStatus.WithLabelValues(name).Set(float64(value)) - } - uptimeSeconds.Add(interval.Seconds()) -} - -func (c *checker) Register(service Checkable) error { - name := service.Name() - if name == "" { - return errors.Errorf("misconfigured check %#v for %v", name, service) - } - - c.srvMutex.Lock() - defer c.srvMutex.Unlock() - c.services[name] = service - return nil -} - -func (c *checker) Unregister(name string) error { - if name == "" { - return errors.Errorf("name cannot be empty") - } - - c.srvMutex.Lock() - defer c.srvMutex.Unlock() - delete(c.services, name) - healthStatus.DeleteLabelValues(name) - return nil -} - -func (c *checker) IsReady() (ready bool, errors map[string]error) { - c.stateMutex.RLock() - defer c.stateMutex.RUnlock() - - ready = true - errors = make(map[string]error, len(c.services)) - - for name, state := range c.ready { - errors[name] = state - - if state != nil { - ready = false - } - } +var _ Checker = (*services.HealthChecker)(nil) - return -} - -func (c *checker) IsHealthy() (healthy bool, errors map[string]error) { - c.stateMutex.RLock() - defer c.stateMutex.RUnlock() - - healthy = true - errors = make(map[string]error, len(c.services)) - - for name, state := range c.healthy { - errors[name] = state - - if state != nil { - healthy = false - } - } - - return +// Checker provides a service which can be probed for system health. +// +//go:generate mockery --quiet --name Checker --output ./mocks/ --case=underscore +type Checker interface { + // Register a service for health checks. + Register(service services.HealthReporter) error + // Unregister a service. + Unregister(name string) error + // IsReady returns the current readiness of the system. + // A system is considered ready if all checks are passing (no errors) + IsReady() (ready bool, errors map[string]error) + // IsHealthy returns the current health of the system. + // A system is considered healthy if all checks are passing (no errors) + IsHealthy() (healthy bool, errors map[string]error) + + Start() error + Close() error } type InBackupHealthReport struct { diff --git a/core/services/health_test.go b/core/services/health_test.go index f8e139af157..3bd0e5d39b2 100644 --- a/core/services/health_test.go +++ b/core/services/health_test.go @@ -5,8 +5,6 @@ import ( "testing" "time" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -14,63 +12,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services" ) -var ErrUnhealthy = errors.New("Unhealthy") - -type boolCheck struct { - name string - healthy bool -} - -func (b boolCheck) Name() string { return b.name } - -func (b boolCheck) Ready() error { - if b.healthy { - return nil - } - return errors.New("Not ready") -} - -func (b boolCheck) HealthReport() map[string]error { - if b.healthy { - return map[string]error{b.name: nil} - } - return map[string]error{b.name: ErrUnhealthy} -} - -func TestCheck(t *testing.T) { - for i, test := range []struct { - checks []services.Checkable - healthy bool - expected map[string]error - }{ - {[]services.Checkable{}, true, map[string]error{}}, - - {[]services.Checkable{boolCheck{"0", true}}, true, map[string]error{"0": nil}}, - - {[]services.Checkable{boolCheck{"0", true}, boolCheck{"1", true}}, true, map[string]error{"0": nil, "1": nil}}, - - {[]services.Checkable{boolCheck{"0", true}, boolCheck{"1", false}}, false, map[string]error{"0": nil, "1": ErrUnhealthy}}, - - {[]services.Checkable{boolCheck{"0", true}, boolCheck{"1", false}, boolCheck{"2", false}}, false, map[string]error{ - "0": nil, - "1": ErrUnhealthy, - "2": ErrUnhealthy, - }}, - } { - c := services.NewChecker() - for _, check := range test.checks { - require.NoError(t, c.Register(check)) - } - - require.NoError(t, c.Start()) - - healthy, results := c.IsHealthy() - - assert.Equal(t, test.healthy, healthy, "case %d", i) - assert.Equal(t, test.expected, results, "case %d", i) - } -} - func TestNewInBackupHealthReport(t *testing.T) { lggr, observed := logger.TestLoggerObserved(t, zapcore.InfoLevel) ibhr := services.NewInBackupHealthReport(1234, lggr) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index bf81064e6a6..20f569a893a 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/lib/pq" - "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" @@ -217,11 +216,25 @@ func TestORM(t *testing.T) { }) t.Run("creates a job with a direct request spec", func(t *testing.T) { - tree, err := toml.LoadFile("../../testdata/tomlspecs/direct-request-spec.toml") - require.NoError(t, err) - jb, err := directrequest.ValidatedDirectRequestSpec(tree.String()) + drSpec := fmt.Sprintf(` + type = "directrequest" + schemaVersion = 1 + evmChainID = "0" + name = "example eth request event spec" + contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" + externalJobID = "%s" + observationSource = """ + ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; + ds1_merge [type=merge left="{}"] + ds1_parse [type=jsonparse path="USD"]; + ds1_multiply [type=multiply times=100]; + ds1 -> ds1_parse -> ds1_multiply; + """ + `, uuid.New()) + + drJob, err := directrequest.ValidatedDirectRequestSpec(drSpec) require.NoError(t, err) - err = orm.CreateJob(&jb) + err = orm.CreateJob(&drJob) require.NoError(t, err) }) @@ -244,64 +257,64 @@ func TestORM(t *testing.T) { }) t.Run("it creates and deletes records for blockhash store jobs", func(t *testing.T) { - jb, err := blockhashstore.ValidatedSpec( + bhsJob, err := blockhashstore.ValidatedSpec( testspecs.GenerateBlockhashStoreSpec(testspecs.BlockhashStoreSpecParams{}).Toml()) require.NoError(t, err) - err = orm.CreateJob(&jb) - require.NoError(t, err) - savedJob, err := orm.FindJob(testutils.Context(t), jb.ID) - require.NoError(t, err) - require.Equal(t, jb.ID, savedJob.ID) - require.Equal(t, jb.Type, savedJob.Type) - require.Equal(t, jb.BlockhashStoreSpec.ID, savedJob.BlockhashStoreSpec.ID) - require.Equal(t, jb.BlockhashStoreSpec.CoordinatorV1Address, savedJob.BlockhashStoreSpec.CoordinatorV1Address) - require.Equal(t, jb.BlockhashStoreSpec.CoordinatorV2Address, savedJob.BlockhashStoreSpec.CoordinatorV2Address) - require.Equal(t, jb.BlockhashStoreSpec.CoordinatorV2PlusAddress, savedJob.BlockhashStoreSpec.CoordinatorV2PlusAddress) - require.Equal(t, jb.BlockhashStoreSpec.WaitBlocks, savedJob.BlockhashStoreSpec.WaitBlocks) - require.Equal(t, jb.BlockhashStoreSpec.LookbackBlocks, savedJob.BlockhashStoreSpec.LookbackBlocks) - require.Equal(t, jb.BlockhashStoreSpec.HeartbeatPeriod, savedJob.BlockhashStoreSpec.HeartbeatPeriod) - require.Equal(t, jb.BlockhashStoreSpec.BlockhashStoreAddress, savedJob.BlockhashStoreSpec.BlockhashStoreAddress) - require.Equal(t, jb.BlockhashStoreSpec.TrustedBlockhashStoreAddress, savedJob.BlockhashStoreSpec.TrustedBlockhashStoreAddress) - require.Equal(t, jb.BlockhashStoreSpec.TrustedBlockhashStoreBatchSize, savedJob.BlockhashStoreSpec.TrustedBlockhashStoreBatchSize) - require.Equal(t, jb.BlockhashStoreSpec.PollPeriod, savedJob.BlockhashStoreSpec.PollPeriod) - require.Equal(t, jb.BlockhashStoreSpec.RunTimeout, savedJob.BlockhashStoreSpec.RunTimeout) - require.Equal(t, jb.BlockhashStoreSpec.EVMChainID, savedJob.BlockhashStoreSpec.EVMChainID) - require.Equal(t, jb.BlockhashStoreSpec.FromAddresses, savedJob.BlockhashStoreSpec.FromAddresses) - err = orm.DeleteJob(jb.ID) - require.NoError(t, err) - _, err = orm.FindJob(testutils.Context(t), jb.ID) + err = orm.CreateJob(&bhsJob) + require.NoError(t, err) + savedJob, err := orm.FindJob(testutils.Context(t), bhsJob.ID) + require.NoError(t, err) + require.Equal(t, bhsJob.ID, savedJob.ID) + require.Equal(t, bhsJob.Type, savedJob.Type) + require.Equal(t, bhsJob.BlockhashStoreSpec.ID, savedJob.BlockhashStoreSpec.ID) + require.Equal(t, bhsJob.BlockhashStoreSpec.CoordinatorV1Address, savedJob.BlockhashStoreSpec.CoordinatorV1Address) + require.Equal(t, bhsJob.BlockhashStoreSpec.CoordinatorV2Address, savedJob.BlockhashStoreSpec.CoordinatorV2Address) + require.Equal(t, bhsJob.BlockhashStoreSpec.CoordinatorV2PlusAddress, savedJob.BlockhashStoreSpec.CoordinatorV2PlusAddress) + require.Equal(t, bhsJob.BlockhashStoreSpec.WaitBlocks, savedJob.BlockhashStoreSpec.WaitBlocks) + require.Equal(t, bhsJob.BlockhashStoreSpec.LookbackBlocks, savedJob.BlockhashStoreSpec.LookbackBlocks) + require.Equal(t, bhsJob.BlockhashStoreSpec.HeartbeatPeriod, savedJob.BlockhashStoreSpec.HeartbeatPeriod) + require.Equal(t, bhsJob.BlockhashStoreSpec.BlockhashStoreAddress, savedJob.BlockhashStoreSpec.BlockhashStoreAddress) + require.Equal(t, bhsJob.BlockhashStoreSpec.TrustedBlockhashStoreAddress, savedJob.BlockhashStoreSpec.TrustedBlockhashStoreAddress) + require.Equal(t, bhsJob.BlockhashStoreSpec.TrustedBlockhashStoreBatchSize, savedJob.BlockhashStoreSpec.TrustedBlockhashStoreBatchSize) + require.Equal(t, bhsJob.BlockhashStoreSpec.PollPeriod, savedJob.BlockhashStoreSpec.PollPeriod) + require.Equal(t, bhsJob.BlockhashStoreSpec.RunTimeout, savedJob.BlockhashStoreSpec.RunTimeout) + require.Equal(t, bhsJob.BlockhashStoreSpec.EVMChainID, savedJob.BlockhashStoreSpec.EVMChainID) + require.Equal(t, bhsJob.BlockhashStoreSpec.FromAddresses, savedJob.BlockhashStoreSpec.FromAddresses) + err = orm.DeleteJob(bhsJob.ID) + require.NoError(t, err) + _, err = orm.FindJob(testutils.Context(t), bhsJob.ID) require.Error(t, err) }) t.Run("it creates and deletes records for blockheaderfeeder jobs", func(t *testing.T) { - jb, err := blockheaderfeeder.ValidatedSpec( + bhsJob, err := blockheaderfeeder.ValidatedSpec( testspecs.GenerateBlockHeaderFeederSpec(testspecs.BlockHeaderFeederSpecParams{}).Toml()) require.NoError(t, err) - err = orm.CreateJob(&jb) - require.NoError(t, err) - savedJob, err := orm.FindJob(testutils.Context(t), jb.ID) - require.NoError(t, err) - require.Equal(t, jb.ID, savedJob.ID) - require.Equal(t, jb.Type, savedJob.Type) - require.Equal(t, jb.BlockHeaderFeederSpec.ID, savedJob.BlockHeaderFeederSpec.ID) - require.Equal(t, jb.BlockHeaderFeederSpec.CoordinatorV1Address, savedJob.BlockHeaderFeederSpec.CoordinatorV1Address) - require.Equal(t, jb.BlockHeaderFeederSpec.CoordinatorV2Address, savedJob.BlockHeaderFeederSpec.CoordinatorV2Address) - require.Equal(t, jb.BlockHeaderFeederSpec.CoordinatorV2PlusAddress, savedJob.BlockHeaderFeederSpec.CoordinatorV2PlusAddress) - require.Equal(t, jb.BlockHeaderFeederSpec.WaitBlocks, savedJob.BlockHeaderFeederSpec.WaitBlocks) - require.Equal(t, jb.BlockHeaderFeederSpec.LookbackBlocks, savedJob.BlockHeaderFeederSpec.LookbackBlocks) - require.Equal(t, jb.BlockHeaderFeederSpec.BlockhashStoreAddress, savedJob.BlockHeaderFeederSpec.BlockhashStoreAddress) - require.Equal(t, jb.BlockHeaderFeederSpec.BatchBlockhashStoreAddress, savedJob.BlockHeaderFeederSpec.BatchBlockhashStoreAddress) - require.Equal(t, jb.BlockHeaderFeederSpec.PollPeriod, savedJob.BlockHeaderFeederSpec.PollPeriod) - require.Equal(t, jb.BlockHeaderFeederSpec.RunTimeout, savedJob.BlockHeaderFeederSpec.RunTimeout) - require.Equal(t, jb.BlockHeaderFeederSpec.EVMChainID, savedJob.BlockHeaderFeederSpec.EVMChainID) - require.Equal(t, jb.BlockHeaderFeederSpec.FromAddresses, savedJob.BlockHeaderFeederSpec.FromAddresses) - require.Equal(t, jb.BlockHeaderFeederSpec.GetBlockhashesBatchSize, savedJob.BlockHeaderFeederSpec.GetBlockhashesBatchSize) - require.Equal(t, jb.BlockHeaderFeederSpec.StoreBlockhashesBatchSize, savedJob.BlockHeaderFeederSpec.StoreBlockhashesBatchSize) - err = orm.DeleteJob(jb.ID) - require.NoError(t, err) - _, err = orm.FindJob(testutils.Context(t), jb.ID) + err = orm.CreateJob(&bhsJob) + require.NoError(t, err) + savedJob, err := orm.FindJob(testutils.Context(t), bhsJob.ID) + require.NoError(t, err) + require.Equal(t, bhsJob.ID, savedJob.ID) + require.Equal(t, bhsJob.Type, savedJob.Type) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.ID, savedJob.BlockHeaderFeederSpec.ID) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.CoordinatorV1Address, savedJob.BlockHeaderFeederSpec.CoordinatorV1Address) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.CoordinatorV2Address, savedJob.BlockHeaderFeederSpec.CoordinatorV2Address) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.CoordinatorV2PlusAddress, savedJob.BlockHeaderFeederSpec.CoordinatorV2PlusAddress) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.WaitBlocks, savedJob.BlockHeaderFeederSpec.WaitBlocks) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.LookbackBlocks, savedJob.BlockHeaderFeederSpec.LookbackBlocks) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.BlockhashStoreAddress, savedJob.BlockHeaderFeederSpec.BlockhashStoreAddress) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.BatchBlockhashStoreAddress, savedJob.BlockHeaderFeederSpec.BatchBlockhashStoreAddress) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.PollPeriod, savedJob.BlockHeaderFeederSpec.PollPeriod) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.RunTimeout, savedJob.BlockHeaderFeederSpec.RunTimeout) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.EVMChainID, savedJob.BlockHeaderFeederSpec.EVMChainID) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.FromAddresses, savedJob.BlockHeaderFeederSpec.FromAddresses) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.GetBlockhashesBatchSize, savedJob.BlockHeaderFeederSpec.GetBlockhashesBatchSize) + require.Equal(t, bhsJob.BlockHeaderFeederSpec.StoreBlockhashesBatchSize, savedJob.BlockHeaderFeederSpec.StoreBlockhashesBatchSize) + err = orm.DeleteJob(bhsJob.ID) + require.NoError(t, err) + _, err = orm.FindJob(testutils.Context(t), bhsJob.ID) require.Error(t, err) }) } @@ -590,7 +603,7 @@ func TestORM_CreateJob_OCRBootstrap(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(testspecs.OCRBootstrapSpec) + jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(testspecs.GetOCRBootstrapSpec()) require.NoError(t, err) err = jobORM.CreateJob(&jb) @@ -787,7 +800,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) const juelsPerFeeCoinSource = ` @@ -803,7 +816,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { err = jobORM.CreateJob(&jb) require.NoError(t, err) - jb2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) jb2.Name = null.StringFrom("Job with same chain id & contract address") @@ -813,7 +826,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { err = jobORM.CreateJob(&jb2) require.Error(t, err) - jb3, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb3, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) jb3.Name = null.StringFrom("Job with different chain id & same contract address") jb3.OCR2OracleSpec.TransmitterID = null.StringFrom(address.String()) @@ -849,7 +862,7 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) t.Run("sending keys or transmitterID must be defined", func(t *testing.T) { @@ -887,12 +900,16 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { keyStore := cltest.NewKeyStore(t, pgtest.NewSqlxDB(t), config.Database()) require.NoError(t, keyStore.OCR2().Add(cltest.DefaultOCR2Key)) - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) - require.NoError(t, err) + var jb job.Job + { + var err error + jb, err = ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) + require.NoError(t, err) + } t.Run("test ETH key validation", func(t *testing.T) { jb.OCR2OracleSpec.Relay = relay.EVM - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no EVM key matching: \"bad key\"") _, evmKey := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -902,7 +919,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Cosmos key validation", func(t *testing.T) { jb.OCR2OracleSpec.Relay = relay.Cosmos - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Cosmos key matching: \"bad key\"") cosmosKey, err := keyStore.Cosmos().Create() @@ -914,7 +931,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Solana key validation", func(t *testing.T) { jb.OCR2OracleSpec.Relay = relay.Solana - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Solana key matching: \"bad key\"") solanaKey, err := keyStore.Solana().Create() @@ -925,7 +942,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Starknet key validation", func(t *testing.T) { jb.OCR2OracleSpec.Relay = relay.StarkNet - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no Starknet key matching: \"bad key\"") starkNetKey, err := keyStore.StarkNet().Create() @@ -936,7 +953,7 @@ func TestORM_ValidateKeyStoreMatch(t *testing.T) { t.Run("test Mercury ETH key validation", func(t *testing.T) { jb.OCR2OracleSpec.PluginType = types.Mercury - err = job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") + err := job.ValidateKeyStoreMatch(jb.OCR2OracleSpec, keyStore, "bad key") require.EqualError(t, err, "no CSA key matching: \"bad key\"") csaKey, err := keyStore.CSA().Create() @@ -979,7 +996,7 @@ func Test_FindJobs(t *testing.T) { require.NoError(t, err) jb2, err := directrequest.ValidatedDirectRequestSpec( - testspecs.DirectRequestSpec, + testspecs.GetDirectRequestSpec(), ) require.NoError(t, err) @@ -987,8 +1004,8 @@ func Test_FindJobs(t *testing.T) { require.NoError(t, err) t.Run("jobs are ordered by latest first", func(t *testing.T) { - jobs, count, err := orm.FindJobs(0, 2) - require.NoError(t, err) + jobs, count, err2 := orm.FindJobs(0, 2) + require.NoError(t, err2) require.Len(t, jobs, 2) assert.Equal(t, count, 2) @@ -1000,8 +1017,8 @@ func Test_FindJobs(t *testing.T) { }) t.Run("jobs respect pagination", func(t *testing.T) { - jobs, count, err := orm.FindJobs(0, 1) - require.NoError(t, err) + jobs, count, err2 := orm.FindJobs(0, 1) + require.NoError(t, err2) require.Len(t, jobs, 1) assert.Equal(t, count, 2) @@ -1071,7 +1088,7 @@ func Test_FindJob(t *testing.T) { ) require.NoError(t, err) - jobOCR2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jobOCR2, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) jobOCR2.OCR2OracleSpec.TransmitterID = null.StringFrom(address.String()) @@ -1120,8 +1137,8 @@ func Test_FindJob(t *testing.T) { t.Run("by id", func(t *testing.T) { ctx, cancel := context.WithTimeout(testutils.Context(t), 5*time.Second) defer cancel() - jb, err := orm.FindJob(ctx, job.ID) - require.NoError(t, err) + jb, err2 := orm.FindJob(ctx, job.ID) + require.NoError(t, err2) assert.Equal(t, jb.ID, job.ID) assert.Equal(t, jb.Name, job.Name) @@ -1133,8 +1150,8 @@ func Test_FindJob(t *testing.T) { }) t.Run("by external job id", func(t *testing.T) { - jb, err := orm.FindJobByExternalJobID(externalJobID) - require.NoError(t, err) + jb, err2 := orm.FindJobByExternalJobID(externalJobID) + require.NoError(t, err2) assert.Equal(t, jb.ID, job.ID) assert.Equal(t, jb.Name, job.Name) @@ -1146,28 +1163,28 @@ func Test_FindJob(t *testing.T) { }) t.Run("by address", func(t *testing.T) { - jbID, err := orm.FindJobIDByAddress(job.OCROracleSpec.ContractAddress, job.OCROracleSpec.EVMChainID) - require.NoError(t, err) + jbID, err2 := orm.FindJobIDByAddress(job.OCROracleSpec.ContractAddress, job.OCROracleSpec.EVMChainID) + require.NoError(t, err2) assert.Equal(t, job.ID, jbID) - _, err = orm.FindJobIDByAddress("not-existing", utils.NewBigI(0)) - require.Error(t, err) - require.ErrorIs(t, err, sql.ErrNoRows) + _, err2 = orm.FindJobIDByAddress("not-existing", utils.NewBigI(0)) + require.Error(t, err2) + require.ErrorIs(t, err2, sql.ErrNoRows) }) t.Run("by address yet chain scoped", func(t *testing.T) { commonAddr := jobSameAddress.OCROracleSpec.ContractAddress // Find job ID for job on chain 1337 with common address. - jbID, err := orm.FindJobIDByAddress(commonAddr, jobSameAddress.OCROracleSpec.EVMChainID) - require.NoError(t, err) + jbID, err2 := orm.FindJobIDByAddress(commonAddr, jobSameAddress.OCROracleSpec.EVMChainID) + require.NoError(t, err2) assert.Equal(t, jobSameAddress.ID, jbID) // Find job ID for job on default evm chain with common address. - jbID, err = orm.FindJobIDByAddress(commonAddr, job.OCROracleSpec.EVMChainID) - require.NoError(t, err) + jbID, err2 = orm.FindJobIDByAddress(commonAddr, job.OCROracleSpec.EVMChainID) + require.NoError(t, err2) assert.Equal(t, job.ID, jbID) }) @@ -1176,8 +1193,8 @@ func Test_FindJob(t *testing.T) { contractID := "0x613a38AC1659769640aaE063C651F48E0250454C" // Find job ID for ocr2 job without feedID. - jbID, err := orm.FindOCR2JobIDByAddress(contractID, nil) - require.NoError(t, err) + jbID, err2 := orm.FindOCR2JobIDByAddress(contractID, nil) + require.NoError(t, err2) assert.Equal(t, jobOCR2.ID, jbID) }) @@ -1187,8 +1204,8 @@ func Test_FindJob(t *testing.T) { feedID := common.HexToHash(ocr2WithFeedID1) // Find job ID for ocr2 job with feed ID - jbID, err := orm.FindOCR2JobIDByAddress(contractID, &feedID) - require.NoError(t, err) + jbID, err2 := orm.FindOCR2JobIDByAddress(contractID, &feedID) + require.NoError(t, err2) assert.Equal(t, jobOCR2WithFeedID1.ID, jbID) }) @@ -1198,8 +1215,8 @@ func Test_FindJob(t *testing.T) { feedID := common.HexToHash(ocr2WithFeedID2) // Find job ID for ocr2 job with feed ID - jbID, err := orm.FindOCR2JobIDByAddress(contractID, &feedID) - require.NoError(t, err) + jbID, err2 := orm.FindOCR2JobIDByAddress(contractID, &feedID) + require.NoError(t, err2) assert.Equal(t, jobOCR2WithFeedID2.ID, jbID) }) @@ -1219,7 +1236,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) + jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) jb.DirectRequestSpec.EVMChainID = utils.NewBigI(0) @@ -1227,8 +1244,8 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { require.NoError(t, err) t.Run("with jobs", func(t *testing.T) { - jbs, err := orm.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) - require.NoError(t, err) + jbs, err2 := orm.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) + require.NoError(t, err2) assert.Len(t, jbs, 1) assert.Equal(t, jb.ID, jbs[0].ID) @@ -1240,8 +1257,8 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { }) t.Run("without jobs", func(t *testing.T) { - jbs, err := orm.FindJobsByPipelineSpecIDs([]int32{-1}) - require.NoError(t, err) + jbs, err2 := orm.FindJobsByPipelineSpecIDs([]int32{-1}) + require.NoError(t, err2) assert.Len(t, jbs, 0) }) @@ -1261,8 +1278,8 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { orm2 := NewTestORM(t, db, legacyChains2, pipelineORM, bridgesORM, keyStore, config.Database()) - jbs, err := orm2.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) - require.NoError(t, err) + jbs, err2 := orm2.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) + require.NoError(t, err2) assert.Len(t, jbs, 1) }) } @@ -1301,8 +1318,8 @@ func Test_FindPipelineRuns(t *testing.T) { require.NoError(t, err) t.Run("with no pipeline runs", func(t *testing.T) { - runs, count, err := orm.PipelineRuns(nil, 0, 10) - require.NoError(t, err) + runs, count, err2 := orm.PipelineRuns(nil, 0, 10) + require.NoError(t, err2) assert.Equal(t, count, 0) assert.Empty(t, runs) }) @@ -1310,8 +1327,8 @@ func Test_FindPipelineRuns(t *testing.T) { t.Run("with a pipeline run", func(t *testing.T) { run := mustInsertPipelineRun(t, pipelineORM, jb) - runs, count, err := orm.PipelineRuns(nil, 0, 10) - require.NoError(t, err) + runs, count, err2 := orm.PipelineRuns(nil, 0, 10) + require.NoError(t, err2) assert.Equal(t, count, 1) actual := runs[0] @@ -1362,8 +1379,8 @@ func Test_PipelineRunsByJobID(t *testing.T) { require.NoError(t, err) t.Run("with no pipeline runs", func(t *testing.T) { - runs, count, err := orm.PipelineRuns(&jb.ID, 0, 10) - require.NoError(t, err) + runs, count, err2 := orm.PipelineRuns(&jb.ID, 0, 10) + require.NoError(t, err2) assert.Equal(t, count, 0) assert.Empty(t, runs) }) @@ -1371,8 +1388,8 @@ func Test_PipelineRunsByJobID(t *testing.T) { t.Run("with a pipeline run", func(t *testing.T) { run := mustInsertPipelineRun(t, pipelineORM, jb) - runs, count, err := orm.PipelineRuns(&jb.ID, 0, 10) - require.NoError(t, err) + runs, count, err2 := orm.PipelineRuns(&jb.ID, 0, 10) + require.NoError(t, err2) assert.Equal(t, 1, count) actual := runs[0] @@ -1531,16 +1548,16 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { require.NoError(t, err) t.Run("with no pipeline runs", func(t *testing.T) { - runs, err := orm.FindPipelineRunsByIDs([]int64{-1}) - require.NoError(t, err) + runs, err2 := orm.FindPipelineRunsByIDs([]int64{-1}) + require.NoError(t, err2) assert.Empty(t, runs) }) t.Run("with a pipeline run", func(t *testing.T) { run := mustInsertPipelineRun(t, pipelineORM, jb) - actual, err := orm.FindPipelineRunsByIDs([]int64{run.ID}) - require.NoError(t, err) + actual, err2 := orm.FindPipelineRunsByIDs([]int64{run.ID}) + require.NoError(t, err2) require.Len(t, actual, 1) actualRun := actual[0] @@ -1570,23 +1587,23 @@ func Test_FindPipelineRunByID(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) + jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) err = orm.CreateJob(&jb) require.NoError(t, err) t.Run("with no pipeline run", func(t *testing.T) { - run, err := orm.FindPipelineRunByID(-1) + run, err2 := orm.FindPipelineRunByID(-1) assert.Equal(t, run, pipeline.Run{}) - require.ErrorIs(t, err, sql.ErrNoRows) + require.ErrorIs(t, err2, sql.ErrNoRows) }) t.Run("with a pipeline run", func(t *testing.T) { run := mustInsertPipelineRun(t, pipelineORM, jb) - actual, err := orm.FindPipelineRunByID(run.ID) - require.NoError(t, err) + actual, err2 := orm.FindPipelineRunByID(run.ID) + require.NoError(t, err2) actualRun := actual // Test pipeline run fields @@ -1615,7 +1632,7 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) + jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) err = orm.CreateJob(&jb) @@ -1654,7 +1671,7 @@ func Test_FindSpecErrorsByJobIDs(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) + jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) err = orm.CreateJob(&jb) @@ -1709,16 +1726,16 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { require.NoError(t, err) t.Run("with no pipeline runs", func(t *testing.T) { - count, err := orm.CountPipelineRunsByJobID(jb.ID) - require.NoError(t, err) + count, err2 := orm.CountPipelineRunsByJobID(jb.ID) + require.NoError(t, err2) assert.Equal(t, int32(0), count) }) t.Run("with a pipeline run", func(t *testing.T) { mustInsertPipelineRun(t, pipelineORM, jb) - count, err := orm.CountPipelineRunsByJobID(jb.ID) - require.NoError(t, err) + count, err2 := orm.CountPipelineRunsByJobID(jb.ID) + require.NoError(t, err2) require.Equal(t, int32(1), count) }) } diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index c98feea72c2..3d858f81320 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -666,13 +666,12 @@ func (_m *ORM) TryRecordError(jobID int32, description string, qopts ...pg.QOpt) _m.Called(_ca...) } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/job/mocks/service_ctx.go b/core/services/job/mocks/service_ctx.go index 2f755a331ee..93ef76619d9 100644 --- a/core/services/job/mocks/service_ctx.go +++ b/core/services/job/mocks/service_ctx.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -41,13 +41,12 @@ func (_m *ServiceCtx) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewServiceCtx interface { +// NewServiceCtx creates a new instance of ServiceCtx. 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 NewServiceCtx(t interface { mock.TestingT Cleanup(func()) -} - -// NewServiceCtx creates a new instance of ServiceCtx. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewServiceCtx(t mockConstructorTestingTNewServiceCtx) *ServiceCtx { +}) *ServiceCtx { mock := &ServiceCtx{} mock.Mock.Test(t) diff --git a/core/services/job/mocks/spawner.go b/core/services/job/mocks/spawner.go index 6f6c3200af8..6866f1fc156 100644 --- a/core/services/job/mocks/spawner.go +++ b/core/services/job/mocks/spawner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -167,13 +167,12 @@ func (_m *Spawner) StartService(ctx context.Context, spec job.Job, qopts ...pg.Q return r0 } -type mockConstructorTestingTNewSpawner interface { +// NewSpawner creates a new instance of Spawner. 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 NewSpawner(t interface { mock.TestingT Cleanup(func()) -} - -// NewSpawner creates a new instance of Spawner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSpawner(t mockConstructorTestingTNewSpawner) *Spawner { +}) *Spawner { mock := &Spawner{} mock.Mock.Test(t) diff --git a/core/services/job/models.go b/core/services/job/models.go index 5787ce5fb5f..a3dfce59996 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -147,6 +147,8 @@ type Job struct { BootstrapSpecID *int32 GatewaySpec *GatewaySpec GatewaySpecID *int32 + EALSpec *EALSpec + EALSpecID *int32 PipelineSpecID int32 PipelineSpec *pipeline.Spec JobSpecErrors []SpecError @@ -772,3 +774,33 @@ func (s *GatewaySpec) SetID(value string) error { s.ID = int32(ID) return nil } + +// EALSpec defines the job spec for the gas station. +type EALSpec struct { + ID int32 + + // ForwarderAddress is the address of EIP2771 forwarder that verifies signature + // and forwards requests to target contracts + ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` + + // EVMChainID defines the chain ID from which the meta-transaction request originates. + EVMChainID *utils.Big `toml:"evmChainID"` + + // FromAddress is the sender address that should be used to send meta-transactions + FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` + + // LookbackBlocks defines the maximum age of blocks to lookback in status tracker + LookbackBlocks int32 `toml:"lookbackBlocks"` + + // PollPeriod defines how frequently EAL status tracker runs + PollPeriod time.Duration `toml:"pollPeriod"` + + // RunTimeout defines the timeout for a single run of EAL status tracker + RunTimeout time.Duration `toml:"runTimeout"` + + // CreatedAt is the time this job was created. + CreatedAt time.Time `toml:"-"` + + // UpdatedAt is the time this job was last updated. + UpdatedAt time.Time `toml:"-"` +} diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 369ce039ad4..cbdd7ebfae6 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -6,10 +6,9 @@ import ( "encoding/json" "fmt" "reflect" + "slices" "time" - "golang.org/x/exp/slices" - "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/jackc/pgconn" @@ -283,15 +282,15 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { if jb.OCR2OracleSpec.PluginType == types.Median { var cfg medianconfig.PluginConfig - err = json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &cfg) - if err != nil { - return errors.Wrap(err, "failed to parse plugin config") + err2 := json.Unmarshal(jb.OCR2OracleSpec.PluginConfig.Bytes(), &cfg) + if err2 != nil { + return errors.Wrap(err2, "failed to parse plugin config") } - feePipeline, err := pipeline.Parse(cfg.JuelsPerFeeCoinPipeline) - if err != nil { - return err + feePipeline, err2 := pipeline.Parse(cfg.JuelsPerFeeCoinPipeline) + if err2 != nil { + return err2 } - if err2 := o.AssertBridgesExist(*feePipeline); err2 != nil { + if err2 = o.AssertBridgesExist(*feePipeline); err2 != nil { return err2 } } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index a886c52f283..05782f95ce8 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -55,7 +55,7 @@ func TestRunner(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) ethKeyStore := keyStore.Eth() - _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -911,7 +911,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { { url, err := url.Parse(responseURL) require.NoError(t, err) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) body := strings.NewReader(`{"value": {"data":{"result":"123.45"}}}`) response, cleanup := client.Patch(url.Path, body) defer cleanup() @@ -1092,7 +1092,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { { url, err := url.Parse(responseURL) require.NoError(t, err) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) body := strings.NewReader(`{"error": "something exploded in EA"}`) response, cleanup := client.Patch(url.Path, body) defer cleanup() diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index d766faa092a..200c25deb37 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -8,8 +8,11 @@ import ( "sync" pkgerrors "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" + relayservices "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -63,7 +66,7 @@ type ( // job. In case a given job type relies upon well-defined startup/shutdown // ordering for services, they are started in the order they are given // and stopped in reverse order. - ServicesForSpec(spec Job, qopts ...pg.QOpt) ([]ServiceCtx, error) + ServicesForSpec(spec Job) ([]ServiceCtx, error) AfterJobCreated(spec Job) BeforeJobDeleted(spec Job) // OnDeleteJob will be called from within DELETE db transaction. Any db @@ -122,7 +125,7 @@ func (js *spawner) Name() string { } func (js *spawner) HealthReport() map[string]error { - return map[string]error{js.Name(): js.StartStopOnce.Healthy()} + return map[string]error{js.Name(): js.Healthy()} } func (js *spawner) startAllServices(ctx context.Context) { @@ -167,7 +170,7 @@ func (js *spawner) stopService(jobID int32) { for i := len(aj.services) - 1; i >= 0; i-- { service := aj.services[i] sLggr := lggr.With("subservice", i, "serviceType", reflect.TypeOf(service)) - if c, ok := service.(services.Checkable); ok { + if c, ok := service.(relayservices.HealthReporter); ok { if err := js.checker.Unregister(c.Name()); err != nil { sLggr.Warnw("Failed to unregister service from health checker", "err", err) } @@ -208,7 +211,7 @@ func (js *spawner) StartService(ctx context.Context, jb Job, qopts ...pg.QOpt) e jb.PipelineSpec.GasLimit = &jb.GasLimit.Uint32 } - srvs, err := delegate.ServicesForSpec(jb, qopts...) + srvs, err := delegate.ServicesForSpec(jb) if err != nil { lggr.Errorw("Error creating services for job", "err", err) cctx, cancel := js.chStop.NewCtx() @@ -227,7 +230,7 @@ func (js *spawner) StartService(ctx context.Context, jb Job, qopts ...pg.QOpt) e lggr.Criticalw("Error starting service for job", "err", err) return err } - if c, ok := srv.(services.Checkable); ok { + if c, ok := srv.(relayservices.HealthReporter); ok { err = js.checker.Register(c) if err != nil { lggr.Errorw("Error registering service with health checker", "err", err) @@ -384,7 +387,7 @@ func (n *NullDelegate) JobType() Type { } // ServicesForSpec does no-op. -func (n *NullDelegate) ServicesForSpec(spec Job, qopts ...pg.QOpt) (s []ServiceCtx, err error) { +func (n *NullDelegate) ServicesForSpec(spec Job) (s []ServiceCtx, err error) { return } diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 7dbf811f783..4e28dcdf062 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -4,8 +4,6 @@ import ( "testing" "time" - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -14,7 +12,7 @@ import ( "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink-relay/pkg/loop" - + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -52,7 +50,7 @@ func (d delegate) JobType() job.Type { } // ServicesForSpec satisfies the job.Delegate interface. -func (d delegate) ServicesForSpec(js job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d delegate) ServicesForSpec(js job.Job) ([]job.ServiceCtx, error) { if js.Type != d.jobType { return nil, nil } @@ -334,7 +332,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { type noopChecker struct{} -func (n noopChecker) Register(service services.Checkable) error { return nil } +func (n noopChecker) Register(service services.HealthReporter) error { return nil } func (n noopChecker) Unregister(name string) error { return nil } diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index cdb085f743e..6c68203f843 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -2,6 +2,7 @@ package keeper import ( "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -54,7 +55,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err error) { if spec.KeeperSpec == nil { return nil, errors.Errorf("Delegate expects a *job.KeeperSpec to be present, got %v", spec) } diff --git a/core/services/keeper/registry_interface.go b/core/services/keeper/registry_interface.go index f54f68fc70d..fd1c2314a41 100644 --- a/core/services/keeper/registry_interface.go +++ b/core/services/keeper/registry_interface.go @@ -185,9 +185,9 @@ func (rw *RegistryWrapper) GetActiveUpkeepIDs(opts *bind.CallOpts) ([]*big.Int, } switch rw.Version { case RegistryVersion_1_0, RegistryVersion_1_1: - cancelledUpkeeps, err := rw.contract1_1.GetCanceledUpkeepList(opts) - if err != nil { - return nil, errors.Wrap(err, "failed to get cancelled upkeeps") + cancelledUpkeeps, err2 := rw.contract1_1.GetCanceledUpkeepList(opts) + if err2 != nil { + return nil, errors.Wrap(err2, "failed to get cancelled upkeeps") } cancelledSet := make(map[int64]bool) for _, upkeepID := range cancelledUpkeeps { diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 6b9bb815a89..99fb54eba4d 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -5,10 +5,11 @@ import ( "time" "github.com/onsi/gomega" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -59,6 +60,8 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( case keeper.RegistryVersion_1_3: registryMock := cltest.NewContractMockReceiver(t, ethClient, keeper.Registry1_3ABI, contractAddress) registryMock.MockResponse("typeAndVersion", "KeeperRegistry 1.3.0").Once() + case keeper.RegistryVersion_2_0, keeper.RegistryVersion_2_1: + t.Fatalf("Unsupported version: %s", version) } registryWrapper, err := keeper.NewRegistryWrapper(j.KeeperSpec.ContractAddress, ethClient) diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 702633e1d08..39f85aedcd9 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -134,6 +134,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { ethTxCreated := cltest.NewAwaiter() txm.On("CreateTransaction", + mock.Anything, mock.MatchedBy(func(txRequest txmgr.TxRequest) bool { return txRequest.FeeLimit == gasLimit }), ). Once(). @@ -178,6 +179,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { ethTxCreated := cltest.NewAwaiter() txm.On("CreateTransaction", + mock.Anything, mock.MatchedBy(func(txRequest txmgr.TxRequest) bool { return txRequest.FeeLimit == gasLimit }), ). Once(). @@ -284,6 +286,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { } gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() txm.On("CreateTransaction", + mock.Anything, mock.MatchedBy(func(txRequest txmgr.TxRequest) bool { return txRequest.FeeLimit == gasLimit }), ). Once(). diff --git a/core/services/keystore/csa.go b/core/services/keystore/csa.go index 4dd01139452..01491b85b35 100644 --- a/core/services/keystore/csa.go +++ b/core/services/keystore/csa.go @@ -23,8 +23,6 @@ type CSA interface { Import(keyJSON []byte, password string) (csakey.KeyV2, error) Export(id string, password string) ([]byte, error) EnsureKey() error - - GetV1KeysAsV2() ([]csakey.KeyV2, error) } type csa struct { @@ -158,21 +156,6 @@ func (ks *csa) EnsureKey() error { return ks.safeAddKey(key) } -func (ks *csa) GetV1KeysAsV2() (keys []csakey.KeyV2, _ error) { - v1Keys, err := ks.orm.GetEncryptedV1CSAKeys() - if err != nil { - return keys, err - } - for _, keyV1 := range v1Keys { - err := keyV1.Unlock(ks.password) - if err != nil { - return keys, err - } - keys = append(keys, keyV1.ToV2()) - } - return keys, nil -} - func (ks *csa) getByID(id string) (csakey.KeyV2, error) { key, found := ks.keyRing.CSA[id] if !found { diff --git a/core/services/keystore/csa_test.go b/core/services/keystore/csa_test.go index 50de926647d..ef2dd1f6893 100644 --- a/core/services/keystore/csa_test.go +++ b/core/services/keystore/csa_test.go @@ -13,7 +13,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_CSAKeyStore_E2E(t *testing.T) { @@ -51,11 +50,11 @@ func Test_CSAKeyStore_E2E(t *testing.T) { require.Equal(t, key, retrievedKey) t.Run("prevents creating more than one key", func(t *testing.T) { - k, err := ks.Create() + k, err2 := ks.Create() assert.Zero(t, k) - assert.Error(t, err) - assert.True(t, errors.Is(err, keystore.ErrCSAKeyExists)) + assert.Error(t, err2) + assert.True(t, errors.Is(err2, keystore.ErrCSAKeyExists)) }) }) @@ -77,18 +76,18 @@ func Test_CSAKeyStore_E2E(t *testing.T) { require.Equal(t, importedKey, retrievedKey) t.Run("prevents importing more than one key", func(t *testing.T) { - k, err := ks.Import(exportJSON, cltest.Password) + k, err2 := ks.Import(exportJSON, cltest.Password) assert.Zero(t, k) - assert.Error(t, err) - assert.Equal(t, fmt.Sprintf("key with ID %s already exists", key.ID()), err.Error()) + assert.Error(t, err2) + assert.Equal(t, fmt.Sprintf("key with ID %s already exists", key.ID()), err2.Error()) }) t.Run("fails to import malformed key", func(t *testing.T) { - k, err := ks.Import([]byte(""), cltest.Password) + k, err2 := ks.Import([]byte(""), cltest.Password) assert.Zero(t, k) - assert.Error(t, err) + assert.Error(t, err2) }) t.Run("fails to export non-existent key", func(t *testing.T) { @@ -127,10 +126,10 @@ func Test_CSAKeyStore_E2E(t *testing.T) { }) t.Run("fails to delete non-existent key", func(t *testing.T) { - k, err := ks.Delete("non-existent") + k, err2 := ks.Delete("non-existent") assert.Zero(t, k) - assert.Error(t, err) + assert.Error(t, err2) }) }) @@ -169,21 +168,4 @@ func Test_CSAKeyStore_E2E(t *testing.T) { require.NoError(t, err) require.Equal(t, 1, len(keys)) }) - - t.Run("returns V1 keys as V2", func(t *testing.T) { - defer reset() - defer require.NoError(t, utils.JustError(db.Exec("DELETE FROM csa_keys"))) - - k, err := csakey.New(cltest.Password, utils.FastScryptParams) - require.NoError(t, err) - - err = utils.JustError(db.Exec(`INSERT INTO csa_keys (public_key, encrypted_private_key, created_at, updated_at) VALUES ($1, $2, NOW(), NOW())`, k.PublicKey, k.EncryptedPrivateKey)) - require.NoError(t, err) - - keys, err := ks.GetV1KeysAsV2() - require.NoError(t, err) - - assert.Len(t, keys, 1) - assert.Equal(t, fmt.Sprintf("CSAKeyV2{PrivateKey: , PublicKey: %s}", keys[0].PublicKey), keys[0].GoString()) - }) } diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index 9909f398bf4..a2b207044c0 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -32,10 +31,6 @@ type Eth interface { Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error Disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error - Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error - - NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (evmtypes.Nonce, error) - IncrementNextSequence(address common.Address, chainID *big.Int, currentNonce evmtypes.Nonce, qopts ...pg.QOpt) error EnsureKeys(chainIDs ...*big.Int) error SubscribeToKeyChanges() (ch chan struct{}, unsub func()) @@ -58,15 +53,19 @@ type Eth interface { type eth struct { *keyManager + keystateORM + q pg.Q subscribers [](chan struct{}) subscribersMu *sync.RWMutex } var _ Eth = ð{} -func newEthKeyStore(km *keyManager) *eth { +func newEthKeyStore(km *keyManager, orm keystateORM, q pg.Q) *eth { return ð{ + keystateORM: orm, keyManager: km, + q: q, subscribers: make([](chan struct{}), 0), subscribersMu: new(sync.RWMutex), } @@ -182,51 +181,6 @@ func (ks *eth) Export(id string, password string) ([]byte, error) { return key.ToEncryptedJSON(password, ks.scryptParams) } -// Get the next nonce for the given key and chain. It is safest to always to go the DB for this -func (ks *eth) NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (nonce evmtypes.Nonce, err error) { - if !ks.exists(address) { - return evmtypes.Nonce(0), errors.Errorf("key with address %s does not exist", address.String()) - } - nonceVal, err := ks.orm.getNextNonce(address, chainID, qopts...) - if err != nil { - return evmtypes.Nonce(0), errors.Wrap(err, "NextSequence failed") - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.String()][chainID.String()] - if !exists { - return evmtypes.Nonce(0), errors.Errorf("state not found for address %s, chainID %s", address, chainID.String()) - } - if state.Disabled { - return evmtypes.Nonce(0), errors.Errorf("state is disabled for address %s, chainID %s", address, chainID.String()) - } - // Always clobber the memory nonce with the DB nonce - state.NextNonce = nonceVal - return evmtypes.Nonce(nonceVal), nil -} - -// IncrementNextNonce increments keys.next_nonce by 1 -func (ks *eth) IncrementNextSequence(address common.Address, chainID *big.Int, currentSequence evmtypes.Nonce, qopts ...pg.QOpt) error { - if !ks.exists(address) { - return errors.Errorf("key with address %s does not exist", address.String()) - } - incrementedNonce, err := ks.orm.incrementNextNonce(address, chainID, currentSequence.Int64(), qopts...) - if err != nil { - return errors.Wrap(err, "failed IncrementNextNonce") - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.String()][chainID.String()] - if !exists { - return errors.Errorf("state not found for address %s, chainID %s", address, chainID.String()) - } - if state.Disabled { - return errors.Errorf("state is disabled for address %s, chainID %s", address, chainID.String()) - } - state.NextNonce = incrementedNonce - return nil -} - func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { ks.lock.Lock() defer ks.lock.Unlock() @@ -240,10 +194,10 @@ func (ks *eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e // caller must hold lock! func (ks *eth) addKey(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) - sql := `INSERT INTO evm.key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) - VALUES ($1, 0, false, $2, NOW(), NOW()) + sql := `INSERT INTO evm.key_states (address, disabled, evm_chain_id, created_at, updated_at) + VALUES ($1, false, $2, NOW(), NOW()) RETURNING *;` - q := ks.orm.q.WithOpts(qopts...) + q := ks.q.WithOpts(qopts...) if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to insert evm_key_state") } @@ -266,7 +220,7 @@ func (ks *eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt // caller must hold lock! func (ks *eth) enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) - q := ks.orm.q.WithOpts(qopts...) + q := ks.q.WithOpts(qopts...) sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 RETURNING *;` if err := q.Get(state, sql, address, chainID.String()); err != nil { @@ -290,9 +244,9 @@ func (ks *eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOpt) error { state := new(ethkey.State) - q := ks.orm.q.WithOpts(qopts...) + q := ks.q.WithOpts(qopts...) sql := `UPDATE evm.key_states SET disabled = false, updated_at = NOW() WHERE address = $1 AND evm_chain_id = $2 - RETURNING id, next_nonce, address, evm_chain_id, disabled, created_at, updated_at;` + RETURNING id, address, evm_chain_id, disabled, created_at, updated_at;` if err := q.Get(state, sql, address, chainID.String()); err != nil { return errors.Wrap(err, "failed to enable state") } @@ -302,30 +256,6 @@ func (ks *eth) disable(address common.Address, chainID *big.Int, qopts ...pg.QOp return nil } -// Reset the key/chain nonce to the given one -func (ks *eth) Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error { - q := ks.orm.q.WithOpts(qopts...) - res, err := q.Exec(`UPDATE evm.key_states SET next_nonce = $1 WHERE address = $2 AND evm_chain_id = $3`, nonce, address, chainID.String()) - if err != nil { - return errors.Wrap(err, "failed to reset state") - } - rowsAffected, err := res.RowsAffected() - if err != nil { - return errors.Wrap(err, "failed to get RowsAffected") - } - if rowsAffected == 0 { - return errors.Errorf("key state not found with address %s and chainID %s", address.Hex(), chainID.String()) - } - ks.lock.Lock() - defer ks.lock.Unlock() - state, exists := ks.keyStates.KeyIDChainID[address.Hex()][chainID.String()] - if !exists { - return errors.Errorf("state not found for address %s, chainID %s", address.Hex(), chainID.String()) - } - state.NextNonce = nonce - return nil -} - func (ks *eth) Delete(id string) (ethkey.KeyV2, error) { ks.lock.Lock() defer ks.lock.Unlock() @@ -554,27 +484,6 @@ func (ks *eth) EnabledAddressesForChain(chainID *big.Int) (addresses []common.Ad return } -func (ks *eth) getV1KeysAsV2() (keys []ethkey.KeyV2, nonces []int64, fundings []bool, _ error) { - v1Keys, err := ks.orm.GetEncryptedV1EthKeys() - if err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to get encrypted v1 eth keys") - } - if len(v1Keys) == 0 { - return nil, nil, nil, nil - } - for _, keyV1 := range v1Keys { - dKey, err := keystore.DecryptKey(keyV1.JSON, ks.password) - if err != nil { - return nil, nil, nil, errors.Wrapf(err, "could not decrypt eth key %s", keyV1.Address.Hex()) - } - keyV2 := ethkey.FromPrivateKey(dKey.PrivateKey) - keys = append(keys, keyV2) - nonces = append(nonces, keyV1.NextNonce) - fundings = append(fundings, keyV1.IsFunding) - } - return keys, nonces, fundings, nil -} - // XXXTestingOnlySetState is only used in tests to manually update a key's state func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { ks.lock.Lock() @@ -587,9 +496,9 @@ func (ks *eth) XXXTestingOnlySetState(state ethkey.State) { panic(fmt.Sprintf("key not found with ID %s", state.KeyID())) } *existingState = state - sql := `UPDATE evm.key_states SET address = :address, next_nonce = :next_nonce, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() + sql := `UPDATE evm.key_states SET address = :address, is_disabled = :is_disabled, evm_chain_id = :evm_chain_id, updated_at = NOW() WHERE address = :address;` - _, err := ks.orm.q.NamedExec(sql, state) + _, err := ks.q.NamedExec(sql, state) if err != nil { panic(err.Error()) } @@ -620,13 +529,6 @@ func (ks *eth) getByID(id string) (ethkey.KeyV2, error) { return key, nil } -func (ks *eth) exists(address common.Address) bool { - ks.lock.RLock() - defer ks.lock.RUnlock() - _, found := ks.keyRing.Eth[address.Hex()] - return found -} - // caller must hold lock! func (ks *eth) enabledKeysForChain(chainID *big.Int) (keys []ethkey.KeyV2) { return ks.keysForChain(chainID, false) @@ -664,24 +566,6 @@ func (ks *eth) add(key ethkey.KeyV2, chainIDs ...*big.Int) (err error) { return err } -func (ks *eth) addWithNonce(key ethkey.KeyV2, chainID *big.Int, nonce int64, isDisabled bool) (err error) { - ks.lock.Lock() - defer ks.lock.Unlock() - err = ks.safeAddKey(key, func(tx pg.Queryer) (merr error) { - state := new(ethkey.State) - sql := `INSERT INTO evm.key_states (address, next_nonce, disabled, evm_chain_id, created_at, updated_at) -VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *;` - if err = ks.orm.q.Get(state, sql, key.Address, nonce, isDisabled, chainID); err != nil { - return errors.Wrap(err, "failed to insert evm_key_state") - } - - ks.keyStates.add(state) - return nil - }) - ks.notify() - return err -} - // notify notifies subscribers that eth keys have changed func (ks *eth) notify() { ks.subscribersMu.RLock() diff --git a/core/services/keystore/eth_internal_test.go b/core/services/keystore/eth_internal_test.go deleted file mode 100644 index da1585bed44..00000000000 --- a/core/services/keystore/eth_internal_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package keystore - -import ( - "fmt" - "testing" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_EthKeyStore(t *testing.T) { - db := pgtest.NewSqlxDB(t) - - keyStore := ExposedNewMaster(t, db, pgtest.NewQConfig(true)) - err := keyStore.Unlock(testutils.Password) - require.NoError(t, err) - ks := keyStore.Eth() - - t.Run("returns V1 keys as V2", func(t *testing.T) { - ethAddress := testutils.NewAddress() - err = utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{"address":"6fdac88ddfd811d130095373986889ed90e0d622","crypto":{"cipher":"aes-128-ctr","ciphertext":"557f5324e770c3d203751c1f0f7fb5076386c49f5b05e3f20b3abb59758fd3c3","cipherparams":{"iv":"bd9472543fab7cc63027cbcd039daff0"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"647b54770a3fda830b4440ae57c44cf7506297295fe4d72b1ff943e3a8ddb94a"},"mac":"0c654ee29ee06b3816fc0040d84ebd648c557144a77ccc55b9568355f53397b3"},"id":"6fdac88d-dfd8-11d1-3009-5373986889ed","version":3}', NOW(), NOW(), 0, false, NULL)`, ethAddress)) - require.NoError(t, err) - - keys, nonces, fundings, err := ks.(*eth).getV1KeysAsV2() - require.NoError(t, err) - - assert.Len(t, keys, 1) - assert.Equal(t, fmt.Sprintf("EthKeyV2{PrivateKey: , Address: %s}", keys[0].Address), keys[0].GoString()) - assert.Equal(t, int64(0), nonces[0]) - assert.Equal(t, false, fundings[0]) - }) -} diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 78131bec133..0fec509a325 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -1,7 +1,6 @@ package keystore_test import ( - "database/sql" "fmt" "math/big" "sort" @@ -15,7 +14,6 @@ import ( "github.com/stretchr/testify/require" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -231,24 +229,24 @@ func Test_EthKeyStore_GetRoundRobinAddress(t *testing.T) { // enabled - simulated // - key 4 // enabled - fixture - k1, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k1, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k1.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Add(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k1.Address, testutils.SimulatedChainID)) - k2, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k2, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k2.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Add(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Disable(k2.Address, testutils.SimulatedChainID)) - k3, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k3, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k3.Address, testutils.SimulatedChainID)) require.NoError(t, ethKeyStore.Enable(k3.Address, testutils.SimulatedChainID)) - k4, _ := cltest.MustInsertRandomKey(t, ethKeyStore, []utils.Big{}) + k4, _ := cltest.MustInsertRandomKeyNoChains(t, ethKeyStore) require.NoError(t, ethKeyStore.Add(k4.Address, testutils.FixtureChainID)) require.NoError(t, ethKeyStore.Enable(k4.Address, testutils.FixtureChainID)) @@ -335,7 +333,7 @@ func Test_EthKeyStore_SignTx(t *testing.T) { keyStore := cltest.NewKeyStore(t, db, config.Database()) ethKeyStore := keyStore.Eth() - k, _ := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + k, _ := cltest.MustInsertRandomKey(t, ethKeyStore) chainID := big.NewInt(evmclient.NullClientChainID) tx := types.NewTransaction(0, testutils.NewAddress(), big.NewInt(53), 21000, big.NewInt(1000000000), []byte{1, 2, 3, 4}) @@ -615,140 +613,6 @@ func Test_EthKeyStore_EnsureKeys(t *testing.T) { }) } -func Test_EthKeyStore_Reset(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - - k1, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.SimulatedChainID) - - newNonce := testutils.NewRandomPositiveInt64() - - t.Run("when no state matches address/chain ID", func(t *testing.T) { - addr := utils.RandomAddress() - cid := testutils.NewRandomEVMChainID() - err := ks.Reset(addr, cid, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID %s", addr.Hex(), cid.String())) - }) - t.Run("when no state matches address", func(t *testing.T) { - addr := utils.RandomAddress() - err := ks.Reset(addr, testutils.FixtureChainID, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID 0", addr.Hex())) - }) - t.Run("when no state matches chain ID", func(t *testing.T) { - cid := testutils.NewRandomEVMChainID() - err := ks.Reset(addr1, cid, newNonce) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key state not found with address %s and chainID %s", addr1.Hex(), cid.String())) - }) - t.Run("resets key with given address and chain ID to the given nonce", func(t *testing.T) { - err := ks.Reset(k1.Address, testutils.FixtureChainID, newNonce) - assert.NoError(t, err) - - nonce, err := ks.NextSequence(k1.Address, testutils.FixtureChainID) - require.NoError(t, err) - - assert.Equal(t, nonce.Int64(), newNonce) - - state, err := ks.GetState(k1.Address.Hex(), testutils.FixtureChainID) - require.NoError(t, err) - assert.Equal(t, nonce.Int64(), state.NextNonce) - - keys, err := ks.GetAll() - require.NoError(t, err) - require.Len(t, keys, 3) - states, err := ks.GetStatesForKeys(keys) - require.NoError(t, err) - require.Len(t, states, 3) - for _, state = range states { - if state.Address.Address() == k1.Address { - assert.Equal(t, nonce.Int64(), state.NextNonce) - } else { - // the other states didn't get updated - assert.Equal(t, int64(0), state.NextNonce) - } - } - }) -} - -func Test_NextSequence(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - randNonce := testutils.NewRandomPositiveInt64() - - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID, randNonce) - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - - nonce, err := ks.NextSequence(addr1, testutils.FixtureChainID) - require.NoError(t, err) - assert.Equal(t, randNonce, nonce.Int64()) - - _, err = ks.NextSequence(addr1, testutils.SimulatedChainID) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("NextSequence failed: key with address %s is not enabled for chain %s: sql: no rows in result set", addr1.Hex(), testutils.SimulatedChainID.String())) - - randAddr1 := utils.RandomAddress() - _, err = ks.NextSequence(randAddr1, testutils.FixtureChainID) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr1.Hex())) - - randAddr2 := utils.RandomAddress() - _, err = ks.NextSequence(randAddr2, testutils.NewRandomEVMChainID()) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr2.Hex())) -} - -func Test_IncrementNextSequence(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - ks := keyStore.Eth() - randNonce := testutils.NewRandomPositiveInt64() - - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID, randNonce) - evmAddr1 := addr1 - cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - - err := ks.IncrementNextSequence(evmAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce-1)) - assert.ErrorIs(t, err, sql.ErrNoRows) - - err = ks.IncrementNextSequence(evmAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce)) - require.NoError(t, err) - var nonce int64 - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) - assert.Equal(t, randNonce+1, nonce) - - err = ks.IncrementNextSequence(evmAddr1, testutils.SimulatedChainID, evmtypes.Nonce(randNonce+1)) - assert.ErrorIs(t, err, sql.ErrNoRows) - - randAddr1 := utils.RandomAddress() - err = ks.IncrementNextSequence(randAddr1, testutils.FixtureChainID, evmtypes.Nonce(randNonce+1)) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr1.Hex())) - - randAddr2 := utils.RandomAddress() - err = ks.IncrementNextSequence(randAddr2, testutils.NewRandomEVMChainID(), evmtypes.Nonce(randNonce+1)) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("key with address %s does not exist", randAddr2.Hex())) - - // verify it didnt get changed by any erroring calls - require.NoError(t, db.Get(&nonce, `SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2`, addr1, testutils.FixtureChainID.String())) - assert.Equal(t, randNonce+1, nonce) -} - func Test_EthKeyStore_Delete(t *testing.T) { t.Parallel() @@ -762,9 +626,9 @@ func Test_EthKeyStore_Delete(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "Key not found") - _, addr1 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - _, addr2 := cltest.MustInsertRandomKey(t, ks, testutils.FixtureChainID) - cltest.MustInsertRandomKey(t, ks, testutils.SimulatedChainID) + _, addr1 := cltest.MustInsertRandomKey(t, ks) + _, addr2 := cltest.MustInsertRandomKey(t, ks) + cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.SimulatedChainID)) require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) @@ -814,20 +678,20 @@ func Test_EthKeyStore_CheckEnabled(t *testing.T) { // enabled - simulated // - key 4 // enabled - fixture - k1, addr1 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k1, addr1 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Add(k1.Address, testutils.FixtureChainID)) require.NoError(t, ks.Enable(k1.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k1.Address, testutils.FixtureChainID)) - k2, addr2 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k2, addr2 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k2.Address, testutils.FixtureChainID)) require.NoError(t, ks.Add(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k2.Address, testutils.FixtureChainID)) require.NoError(t, ks.Enable(k2.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Disable(k2.Address, testutils.SimulatedChainID)) - k3, addr3 := cltest.MustInsertRandomKey(t, ks, []utils.Big{}) + k3, addr3 := cltest.MustInsertRandomKeyNoChains(t, ks) require.NoError(t, ks.Add(k3.Address, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(k3.Address, testutils.SimulatedChainID)) diff --git a/core/services/keystore/keys/ethkey/key.go b/core/services/keystore/keys/ethkey/key.go index 2ca671b2cda..4201251e34f 100644 --- a/core/services/keystore/keys/ethkey/key.go +++ b/core/services/keystore/keys/ethkey/key.go @@ -19,13 +19,6 @@ type Key struct { CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` DeletedAt *time.Time `json:"-"` - // This is the nonce that should be used for the next transaction. - // Conceptually equivalent to geth's `PendingNonceAt` but more reliable - // because we have a better view of our own transactions - // NOTE: Be cautious about using this field, it is provided for convenience - // only, can go out of date, and should not be relied upon. The source of - // truth is always the database row for the key. - NextNonce int64 `json:"-"` // IsFunding marks the address as being used for rescuing the node and the pending transactions // Only one key can be IsFunding=true at a time. IsFunding bool diff --git a/core/services/keystore/keys/ethkey/models.go b/core/services/keystore/keys/ethkey/models.go index 1afab408dbe..b90503c3ed6 100644 --- a/core/services/keystore/keys/ethkey/models.go +++ b/core/services/keystore/keys/ethkey/models.go @@ -10,13 +10,10 @@ type State struct { ID int32 Address EIP55Address EVMChainID utils.Big - // NextNonce is used for convenience and rendering in UI but the source of - // truth is always the DB - NextNonce int64 - Disabled bool - CreatedAt time.Time - UpdatedAt time.Time - lastUsed time.Time + Disabled bool + CreatedAt time.Time + UpdatedAt time.Time + lastUsed time.Time } func (s State) KeyID() string { diff --git a/core/services/keystore/keys/keystest/keystest.go b/core/services/keystore/keys/keystest/keystest.go new file mode 100644 index 00000000000..9265dc6e189 --- /dev/null +++ b/core/services/keystore/keys/keystest/keystest.go @@ -0,0 +1,15 @@ +package keystest + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" +) + +func NewP2PKeyV2(t *testing.T) p2pkey.KeyV2 { + k, err := p2pkey.NewV2() + require.NoError(t, err) + return k +} diff --git a/core/services/keystore/keystoretest.go b/core/services/keystore/keystoretest.go new file mode 100644 index 00000000000..0b5ce4e0057 --- /dev/null +++ b/core/services/keystore/keystoretest.go @@ -0,0 +1,81 @@ +package keystore + +import ( + "errors" + "sync" + + "github.com/smartcontractkit/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// memoryORM is an in-memory version of the keystore. This is +// only intended to be used in tests to avoid DB lock contention on +// the single DB row that stores the key material. +// +// Note: we store `q` on the struct since `saveEncryptedKeyRing` needs +// to support DB callbacks. +type memoryORM struct { + keyRing *encryptedKeyRing + q pg.Queryer + mu sync.RWMutex +} + +func (o *memoryORM) isEmpty() (bool, error) { + return false, nil +} + +func (o *memoryORM) saveEncryptedKeyRing(kr *encryptedKeyRing, callbacks ...func(pg.Queryer) error) (err error) { + o.mu.Lock() + defer o.mu.Unlock() + o.keyRing = kr + for _, c := range callbacks { + err = errors.Join(err, c(o.q)) + } + return +} + +func (o *memoryORM) getEncryptedKeyRing() (encryptedKeyRing, error) { + o.mu.RLock() + defer o.mu.RUnlock() + if o.keyRing == nil { + return encryptedKeyRing{}, nil + } + return *o.keyRing, nil +} + +func newInMemoryORM(q pg.Queryer) *memoryORM { + return &memoryORM{q: q} +} + +// NewInMemory sets up a keystore which NOOPs attempts to access the `encrypted_key_rings` table. Accessing `evm.key_states` +// will still hit the DB. +func NewInMemory(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg pg.QConfig) *master { + dbORM := NewORM(db, lggr, cfg) + memoryORM := newInMemoryORM(dbORM.q) + + km := &keyManager{ + orm: memoryORM, + keystateORM: dbORM, + scryptParams: scryptParams, + lock: &sync.RWMutex{}, + logger: lggr.Named("KeyStore"), + } + + return &master{ + keyManager: km, + cosmos: newCosmosKeyStore(km), + csa: newCSAKeyStore(km), + eth: newEthKeyStore(km, dbORM, dbORM.q), + ocr: newOCRKeyStore(km), + ocr2: newOCR2KeyStore(km), + p2p: newP2PKeyStore(km), + solana: newSolanaKeyStore(km), + starknet: newStarkNetKeyStore(km), + vrf: newVRFKeyStore(km), + dkgSign: newDKGSignKeyStore(km), + dkgEncrypt: newDKGEncryptKeyStore(km), + } +} diff --git a/core/services/keystore/master.go b/core/services/keystore/master.go index ab4c3256c5c..fb28202b527 100644 --- a/core/services/keystore/master.go +++ b/core/services/keystore/master.go @@ -74,8 +74,10 @@ func New(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg p } func newMaster(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, cfg pg.QConfig) *master { + orm := NewORM(db, lggr, cfg) km := &keyManager{ - orm: NewORM(db, lggr, cfg), + orm: orm, + keystateORM: orm, scryptParams: scryptParams, lock: &sync.RWMutex{}, logger: lggr.Named("KeyStore"), @@ -85,7 +87,7 @@ func newMaster(db *sqlx.DB, scryptParams utils.ScryptParams, lggr logger.Logger, keyManager: km, cosmos: newCosmosKeyStore(km), csa: newCSAKeyStore(km), - eth: newEthKeyStore(km), + eth: newEthKeyStore(km, orm, orm.q), ocr: newOCRKeyStore(km), ocr2: newOCR2KeyStore(km), p2p: newP2PKeyStore(km), @@ -141,17 +143,19 @@ func (ks *master) VRF() VRF { return ks.vrf } -func (ks *master) IsEmpty() (bool, error) { - var count int64 - err := ks.orm.q.QueryRow("SELECT count(*) FROM encrypted_key_rings").Scan(&count) - if err != nil { - return false, err - } - return count == 0, nil +type ORM interface { + isEmpty() (bool, error) + saveEncryptedKeyRing(*encryptedKeyRing, ...func(pg.Queryer) error) error + getEncryptedKeyRing() (encryptedKeyRing, error) +} + +type keystateORM interface { + loadKeyStates() (*keyStates, error) } type keyManager struct { - orm ksORM + orm ORM + keystateORM keystateORM scryptParams utils.ScryptParams keyRing *keyRing keyStates *keyStates @@ -160,6 +164,10 @@ type keyManager struct { logger logger.Logger } +func (km *keyManager) IsEmpty() (bool, error) { + return km.orm.isEmpty() +} + func (km *keyManager) Unlock(password string) error { km.lock.Lock() defer km.lock.Unlock() @@ -181,7 +189,7 @@ func (km *keyManager) Unlock(password string) error { kr.logPubKeys(km.logger) km.keyRing = kr - ks, err := km.orm.loadKeyStates() + ks, err := km.keystateORM.loadKeyStates() if err != nil { return errors.Wrap(err, "unable to load key states") } diff --git a/core/services/keystore/master_test.go b/core/services/keystore/master_test.go index d1c09c7b61c..7a280cc6756 100644 --- a/core/services/keystore/master_test.go +++ b/core/services/keystore/master_test.go @@ -45,7 +45,7 @@ func TestMasterKeystore_Unlock_Save(t *testing.T) { t.Run("won't load a saved keyRing if the password is incorrect", func(t *testing.T) { defer reset() require.NoError(t, keyStore.Unlock(cltest.Password)) - cltest.MustAddRandomKeyToKeystore(t, keyStore.Eth()) // need at least 1 key to encrypt + cltest.MustInsertRandomKey(t, keyStore.Eth()) // need at least 1 key to encrypt cltest.AssertCount(t, db, tableName, 1) keyStore.ResetXXXTestOnly() cltest.AssertCount(t, db, tableName, 1) diff --git a/core/services/keystore/mocks/cosmos.go b/core/services/keystore/mocks/cosmos.go index ff565ff23b3..b8d5d56c373 100644 --- a/core/services/keystore/mocks/cosmos.go +++ b/core/services/keystore/mocks/cosmos.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -189,13 +189,12 @@ func (_m *Cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) return r0, r1 } -type mockConstructorTestingTNewCosmos interface { +// NewCosmos creates a new instance of Cosmos. 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 NewCosmos(t interface { mock.TestingT Cleanup(func()) -} - -// NewCosmos creates a new instance of Cosmos. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCosmos(t mockConstructorTestingTNewCosmos) *Cosmos { +}) *Cosmos { mock := &Cosmos{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/csa.go b/core/services/keystore/mocks/csa.go index 9996b86c8af..4f4e02a2fe6 100644 --- a/core/services/keystore/mocks/csa.go +++ b/core/services/keystore/mocks/csa.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -165,32 +165,6 @@ func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { return r0, r1 } -// GetV1KeysAsV2 provides a mock function with given fields: -func (_m *CSA) GetV1KeysAsV2() ([]csakey.KeyV2, error) { - ret := _m.Called() - - var r0 []csakey.KeyV2 - var r1 error - if rf, ok := ret.Get(0).(func() ([]csakey.KeyV2, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []csakey.KeyV2); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]csakey.KeyV2) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // Import provides a mock function with given fields: keyJSON, password func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { ret := _m.Called(keyJSON, password) @@ -215,13 +189,12 @@ func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { return r0, r1 } -type mockConstructorTestingTNewCSA interface { +// NewCSA creates a new instance of CSA. 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 NewCSA(t interface { mock.TestingT Cleanup(func()) -} - -// NewCSA creates a new instance of CSA. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewCSA(t mockConstructorTestingTNewCSA) *CSA { +}) *CSA { mock := &CSA{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/dkg_encrypt.go b/core/services/keystore/mocks/dkg_encrypt.go index eac29204aba..e1f83888c48 100644 --- a/core/services/keystore/mocks/dkg_encrypt.go +++ b/core/services/keystore/mocks/dkg_encrypt.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -189,13 +189,12 @@ func (_m *DKGEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key return r0, r1 } -type mockConstructorTestingTNewDKGEncrypt interface { +// NewDKGEncrypt creates a new instance of DKGEncrypt. 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 NewDKGEncrypt(t interface { mock.TestingT Cleanup(func()) -} - -// NewDKGEncrypt creates a new instance of DKGEncrypt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDKGEncrypt(t mockConstructorTestingTNewDKGEncrypt) *DKGEncrypt { +}) *DKGEncrypt { mock := &DKGEncrypt{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/dkg_sign.go b/core/services/keystore/mocks/dkg_sign.go index 80f3e9a8e29..ed1aa756a6d 100644 --- a/core/services/keystore/mocks/dkg_sign.go +++ b/core/services/keystore/mocks/dkg_sign.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -189,13 +189,12 @@ func (_m *DKGSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, erro return r0, r1 } -type mockConstructorTestingTNewDKGSign interface { +// NewDKGSign creates a new instance of DKGSign. 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 NewDKGSign(t interface { mock.TestingT Cleanup(func()) -} - -// NewDKGSign creates a new instance of DKGSign. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDKGSign(t mockConstructorTestingTNewDKGSign) *DKGSign { +}) *DKGSign { mock := &DKGSign{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index bb539d8b7ac..6a076e130d1 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -6,15 +6,13 @@ import ( big "math/big" common "github.com/ethereum/go-ethereum/common" - coretypes "github.com/ethereum/go-ethereum/core/types" - ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mock "github.com/stretchr/testify/mock" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + types "github.com/ethereum/go-ethereum/core/types" ) // Eth is an autogenerated mock type for the Eth type @@ -465,97 +463,24 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et return r0, r1 } -// IncrementNextSequence provides a mock function with given fields: address, chainID, currentNonce, qopts -func (_m *Eth) IncrementNextSequence(address common.Address, chainID *big.Int, currentNonce types.Nonce, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, currentNonce) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, types.Nonce, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, currentNonce, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NextSequence provides a mock function with given fields: address, chainID, qopts -func (_m *Eth) NextSequence(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (types.Nonce, error) { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 types.Nonce - var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) (types.Nonce, error)); ok { - return rf(address, chainID, qopts...) - } - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) types.Nonce); ok { - r0 = rf(address, chainID, qopts...) - } else { - r0 = ret.Get(0).(types.Nonce) - } - - if rf, ok := ret.Get(1).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { - r1 = rf(address, chainID, qopts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Reset provides a mock function with given fields: address, chainID, nonce, qopts -func (_m *Eth) Reset(address common.Address, chainID *big.Int, nonce int64, qopts ...pg.QOpt) error { - _va := make([]interface{}, len(qopts)) - for _i := range qopts { - _va[_i] = qopts[_i] - } - var _ca []interface{} - _ca = append(_ca, address, chainID, nonce) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 error - if rf, ok := ret.Get(0).(func(common.Address, *big.Int, int64, ...pg.QOpt) error); ok { - r0 = rf(address, chainID, nonce, qopts...) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // SignTx provides a mock function with given fields: fromAddress, tx, chainID -func (_m *Eth) SignTx(fromAddress common.Address, tx *coretypes.Transaction, chainID *big.Int) (*coretypes.Transaction, error) { +func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { ret := _m.Called(fromAddress, tx, chainID) - var r0 *coretypes.Transaction + var r0 *types.Transaction var r1 error - if rf, ok := ret.Get(0).(func(common.Address, *coretypes.Transaction, *big.Int) (*coretypes.Transaction, error)); ok { + if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { return rf(fromAddress, tx, chainID) } - if rf, ok := ret.Get(0).(func(common.Address, *coretypes.Transaction, *big.Int) *coretypes.Transaction); ok { + if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) *types.Transaction); ok { r0 = rf(fromAddress, tx, chainID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*coretypes.Transaction) + r0 = ret.Get(0).(*types.Transaction) } } - if rf, ok := ret.Get(1).(func(common.Address, *coretypes.Transaction, *big.Int) error); ok { + if rf, ok := ret.Get(1).(func(common.Address, *types.Transaction, *big.Int) error); ok { r1 = rf(fromAddress, tx, chainID) } else { r1 = ret.Error(1) @@ -602,13 +527,12 @@ func (_m *Eth) XXXTestingOnlySetState(_a0 ethkey.State) { _m.Called(_a0) } -type mockConstructorTestingTNewEth interface { +// NewEth creates a new instance of Eth. 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 NewEth(t interface { mock.TestingT Cleanup(func()) -} - -// NewEth creates a new instance of Eth. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewEth(t mockConstructorTestingTNewEth) *Eth { +}) *Eth { mock := &Eth{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index e8b4775d662..d29d2fa4692 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -226,13 +226,12 @@ func (_m *Master) VRF() keystore.VRF { return r0 } -type mockConstructorTestingTNewMaster interface { +// NewMaster creates a new instance of Master. 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 NewMaster(t interface { mock.TestingT Cleanup(func()) -} - -// NewMaster creates a new instance of Master. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewMaster(t mockConstructorTestingTNewMaster) *Master { +}) *Master { mock := &Master{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/ocr.go b/core/services/keystore/mocks/ocr.go index e7737be90c0..505eaa0e46e 100644 --- a/core/services/keystore/mocks/ocr.go +++ b/core/services/keystore/mocks/ocr.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -164,32 +164,6 @@ func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { return r0, r1 } -// GetV1KeysAsV2 provides a mock function with given fields: -func (_m *OCR) GetV1KeysAsV2() ([]ocrkey.KeyV2, error) { - ret := _m.Called() - - var r0 []ocrkey.KeyV2 - var r1 error - if rf, ok := ret.Get(0).(func() ([]ocrkey.KeyV2, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []ocrkey.KeyV2); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]ocrkey.KeyV2) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // Import provides a mock function with given fields: keyJSON, password func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { ret := _m.Called(keyJSON, password) @@ -214,13 +188,12 @@ func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { return r0, r1 } -type mockConstructorTestingTNewOCR interface { +// NewOCR creates a new instance of OCR. 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 NewOCR(t interface { mock.TestingT Cleanup(func()) -} - -// NewOCR creates a new instance of OCR. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOCR(t mockConstructorTestingTNewOCR) *OCR { +}) *OCR { mock := &OCR{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/ocr2.go b/core/services/keystore/mocks/ocr2.go index 15732b62d40..30d870dcdc7 100644 --- a/core/services/keystore/mocks/ocr2.go +++ b/core/services/keystore/mocks/ocr2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -219,13 +219,12 @@ func (_m *OCR2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, erro return r0, r1 } -type mockConstructorTestingTNewOCR2 interface { +// NewOCR2 creates a new instance of OCR2. 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 NewOCR2(t interface { mock.TestingT Cleanup(func()) -} - -// NewOCR2 creates a new instance of OCR2. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOCR2(t mockConstructorTestingTNewOCR2) *OCR2 { +}) *OCR2 { mock := &OCR2{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/p2p.go b/core/services/keystore/mocks/p2p.go index cb4bef6dc27..c91be5a4a92 100644 --- a/core/services/keystore/mocks/p2p.go +++ b/core/services/keystore/mocks/p2p.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -188,32 +188,6 @@ func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { return r0, r1 } -// GetV1KeysAsV2 provides a mock function with given fields: -func (_m *P2P) GetV1KeysAsV2() ([]p2pkey.KeyV2, error) { - ret := _m.Called() - - var r0 []p2pkey.KeyV2 - var r1 error - if rf, ok := ret.Get(0).(func() ([]p2pkey.KeyV2, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() []p2pkey.KeyV2); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]p2pkey.KeyV2) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // Import provides a mock function with given fields: keyJSON, password func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { ret := _m.Called(keyJSON, password) @@ -238,13 +212,12 @@ func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { return r0, r1 } -type mockConstructorTestingTNewP2P interface { +// NewP2P creates a new instance of P2P. 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 NewP2P(t interface { mock.TestingT Cleanup(func()) -} - -// NewP2P creates a new instance of P2P. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewP2P(t mockConstructorTestingTNewP2P) *P2P { +}) *P2P { mock := &P2P{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/solana.go b/core/services/keystore/mocks/solana.go index 663947268e2..66357e32b93 100644 --- a/core/services/keystore/mocks/solana.go +++ b/core/services/keystore/mocks/solana.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -217,13 +217,12 @@ func (_m *Solana) Sign(ctx context.Context, id string, msg []byte) ([]byte, erro return r0, r1 } -type mockConstructorTestingTNewSolana interface { +// NewSolana creates a new instance of Solana. 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 NewSolana(t interface { mock.TestingT Cleanup(func()) -} - -// NewSolana creates a new instance of Solana. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSolana(t mockConstructorTestingTNewSolana) *Solana { +}) *Solana { mock := &Solana{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/starknet.go b/core/services/keystore/mocks/starknet.go index cd8ed646d17..ff9b52d7136 100644 --- a/core/services/keystore/mocks/starknet.go +++ b/core/services/keystore/mocks/starknet.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -188,13 +188,12 @@ func (_m *StarkNet) Import(keyJSON []byte, password string) (starkkey.Key, error return r0, r1 } -type mockConstructorTestingTNewStarkNet interface { +// NewStarkNet creates a new instance of StarkNet. 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 NewStarkNet(t interface { mock.TestingT Cleanup(func()) -} - -// NewStarkNet creates a new instance of StarkNet. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewStarkNet(t mockConstructorTestingTNewStarkNet) *StarkNet { +}) *StarkNet { mock := &StarkNet{} mock.Mock.Test(t) diff --git a/core/services/keystore/mocks/vrf.go b/core/services/keystore/mocks/vrf.go index 0aef5b26e7e..5aa15dca59e 100644 --- a/core/services/keystore/mocks/vrf.go +++ b/core/services/keystore/mocks/vrf.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -177,32 +177,6 @@ func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { return r0, r1 } -// GetV1KeysAsV2 provides a mock function with given fields: password -func (_m *VRF) GetV1KeysAsV2(password string) ([]vrfkey.KeyV2, error) { - ret := _m.Called(password) - - var r0 []vrfkey.KeyV2 - var r1 error - if rf, ok := ret.Get(0).(func(string) ([]vrfkey.KeyV2, error)); ok { - return rf(password) - } - if rf, ok := ret.Get(0).(func(string) []vrfkey.KeyV2); ok { - r0 = rf(password) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]vrfkey.KeyV2) - } - } - - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(password) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - // Import provides a mock function with given fields: keyJSON, password func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { ret := _m.Called(keyJSON, password) @@ -227,13 +201,12 @@ func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { return r0, r1 } -type mockConstructorTestingTNewVRF interface { +// NewVRF creates a new instance of VRF. 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 NewVRF(t interface { mock.TestingT Cleanup(func()) -} - -// NewVRF creates a new instance of VRF. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewVRF(t mockConstructorTestingTNewVRF) *VRF { +}) *VRF { mock := &VRF{} mock.Mock.Test(t) diff --git a/core/services/keystore/ocr.go b/core/services/keystore/ocr.go index fcaaf928943..dda5bfa13c3 100644 --- a/core/services/keystore/ocr.go +++ b/core/services/keystore/ocr.go @@ -19,8 +19,6 @@ type OCR interface { Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) Export(id string, password string) ([]byte, error) EnsureKey() error - - GetV1KeysAsV2() ([]ocrkey.KeyV2, error) } // KeyNotFoundError is returned when we don't find a requested key @@ -156,21 +154,6 @@ func (ks *ocr) EnsureKey() error { return ks.safeAddKey(key) } -func (ks *ocr) GetV1KeysAsV2() (keys []ocrkey.KeyV2, _ error) { - v1Keys, err := ks.orm.GetEncryptedV1OCRKeys() - if err != nil { - return keys, err - } - for _, keyV1 := range v1Keys { - pk, err := keyV1.Decrypt(ks.password) - if err != nil { - return keys, err - } - keys = append(keys, pk.ToV2()) - } - return keys, nil -} - func (ks *ocr) getByID(id string) (ocrkey.KeyV2, error) { key, found := ks.keyRing.OCR[id] if !found { diff --git a/core/services/keystore/ocr_test.go b/core/services/keystore/ocr_test.go index 96765836926..5698352ec30 100644 --- a/core/services/keystore/ocr_test.go +++ b/core/services/keystore/ocr_test.go @@ -1,14 +1,12 @@ package keystore_test import ( - "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -113,24 +111,4 @@ func Test_OCRKeyStore_E2E(t *testing.T) { require.NoError(t, err) require.Equal(t, "7cfd89bbb018e4778a44fd61172e8834dd24b4a2baf61ead795143b117221c61", importedKey.ID()) }) - - t.Run("", func(t *testing.T) { - defer reset() - defer require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_ocr_key_bundles"))) - - ocr1 := utils.NewHash() - b, err := ocrkey.New() - require.NoError(t, err) - eb, err := b.Encrypt(cltest.Password, utils.FastScryptParams) - require.NoError(t, err) - - err = utils.JustError(db.Exec(`INSERT INTO encrypted_ocr_key_bundles (id, on_chain_signing_address, off_chain_public_key, encrypted_private_keys, created_at, updated_at, config_public_key, deleted_at) VALUES ($1, $2, $3, $4, NOW(), NOW(), $5, NULL)`, ocr1, testutils.NewAddress(), utils.NewHash(), eb.EncryptedPrivateKeys, utils.NewHash())) - require.NoError(t, err) - - keys, err := ks.GetV1KeysAsV2() - require.NoError(t, err) - - assert.Len(t, keys, 1) - assert.Equal(t, fmt.Sprintf("OCRKeyV2{ID: %s}", keys[0].ID()), keys[0].GoString()) - }) } diff --git a/core/services/keystore/orm.go b/core/services/keystore/orm.go index 1396b544205..6f612105ea9 100644 --- a/core/services/keystore/orm.go +++ b/core/services/keystore/orm.go @@ -2,17 +2,11 @@ package keystore import ( "database/sql" - "math/big" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/smartcontractkit/sqlx" ) @@ -30,6 +24,15 @@ type ksORM struct { lggr logger.Logger } +func (orm ksORM) isEmpty() (bool, error) { + var count int64 + err := orm.q.QueryRow("SELECT count(*) FROM encrypted_key_rings").Scan(&count) + if err != nil { + return false, err + } + return count == 0, nil +} + func (orm ksORM) saveEncryptedKeyRing(kr *encryptedKeyRing, callbacks ...func(pg.Queryer) error) error { return orm.q.Transaction(func(tx pg.Queryer) error { _, err := tx.Exec(` @@ -67,7 +70,7 @@ func (orm ksORM) getEncryptedKeyRing() (kr encryptedKeyRing, err error) { func (orm ksORM) loadKeyStates() (*keyStates, error) { ks := newKeyStates() var ethkeystates []*ethkey.State - if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, next_nonce, disabled, created_at, updated_at FROM evm.key_states`); err != nil { + if err := orm.q.Select(ðkeystates, `SELECT id, address, evm_chain_id, disabled, created_at, updated_at FROM evm.key_states`); err != nil { return ks, errors.Wrap(err, "error loading evm.key_states from DB") } for _, state := range ethkeystates { @@ -75,42 +78,3 @@ func (orm ksORM) loadKeyStates() (*keyStates, error) { } return ks, nil } - -// getNextNonce returns evm.key_states.next_nonce for the given address -func (orm ksORM) getNextNonce(address common.Address, chainID *big.Int, qopts ...pg.QOpt) (nonce int64, err error) { - q := orm.q.WithOpts(qopts...) - err = q.Get(&nonce, "SELECT next_nonce FROM evm.key_states WHERE address = $1 AND evm_chain_id = $2 AND disabled = false", address, chainID.String()) - if errors.Is(err, sql.ErrNoRows) { - return 0, errors.Wrapf(sql.ErrNoRows, "key with address %s is not enabled for chain %s", address.Hex(), chainID.String()) - } - return nonce, errors.Wrap(err, "failed to load next nonce") -} - -// incrementNextNonce increments evm.key_states.next_nonce by 1 -func (orm ksORM) incrementNextNonce(address common.Address, chainID *big.Int, currentNonce int64, qopts ...pg.QOpt) (incrementedNonce int64, err error) { - q := orm.q.WithOpts(qopts...) - err = q.Get(&incrementedNonce, "UPDATE evm.key_states SET next_nonce = next_nonce + 1, updated_at = NOW() WHERE address = $1 AND next_nonce = $2 AND evm_chain_id = $3 AND disabled = false RETURNING next_nonce", address, currentNonce, chainID.String()) - return incrementedNonce, errors.Wrap(err, "IncrementNextNonce failed to update keys") -} - -// ~~~~~~~~~~~~~~~~~~~~ LEGACY FUNCTIONS FOR V1 MIGRATION ~~~~~~~~~~~~~~~~~~~~ - -func (orm ksORM) GetEncryptedV1CSAKeys() (retrieved []csakey.Key, err error) { - return retrieved, orm.q.Select(&retrieved, `SELECT * FROM csa_keys`) -} - -func (orm ksORM) GetEncryptedV1EthKeys() (retrieved []ethkey.Key, err error) { - return retrieved, orm.q.Select(&retrieved, `SELECT * FROM keys WHERE deleted_at IS NULL`) -} - -func (orm ksORM) GetEncryptedV1OCRKeys() (retrieved []ocrkey.EncryptedKeyBundle, err error) { - return retrieved, orm.q.Select(&retrieved, `SELECT * FROM encrypted_ocr_key_bundles WHERE deleted_at IS NULL`) -} - -func (orm ksORM) GetEncryptedV1P2PKeys() (retrieved []p2pkey.EncryptedP2PKey, err error) { - return retrieved, orm.q.Select(&retrieved, `SELECT * FROM encrypted_p2p_keys WHERE deleted_at IS NULL`) -} - -func (orm ksORM) GetEncryptedV1VRFKeys() (retrieved []vrfkey.EncryptedVRFKey, err error) { - return retrieved, orm.q.Select(&retrieved, `SELECT * FROM encrypted_vrf_keys WHERE deleted_at IS NULL`) -} diff --git a/core/services/keystore/orm_test.go b/core/services/keystore/orm_test.go deleted file mode 100644 index 3264b3b0178..00000000000 --- a/core/services/keystore/orm_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package keystore_test - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/libp2p/go-libp2p-core/peer" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/multierr" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func Test_ORM(t *testing.T) { - db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(false) - - orm := keystore.NewORM(db, logger.TestLogger(t), cfg) - - csa := csakey.MustNewV2XXXTestingOnly(big.NewInt(42)) - eth1 := testutils.NewAddress() - eth2 := testutils.NewAddress() - ocr1 := utils.NewHash() - ocr2 := utils.NewHash() - p1 := cltest.MustRandomP2PPeerID(t) - p2 := cltest.MustRandomP2PPeerID(t) - v1 := vrfkey.MustNewV2XXXTestingOnly(big.NewInt(1)) - v2 := vrfkey.MustNewV2XXXTestingOnly(big.NewInt(2)) - err := multierr.Combine( - // csakeys has no deleted_at column - utils.JustError(db.Exec(`INSERT INTO csa_keys (public_key, encrypted_private_key, created_at, updated_at) VALUES ($1, '{}', NOW(), NOW())`, csa.PublicKey)), - - // two per key-type, one deleted and one not deleted - utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), 0, false, NULL)`, eth1)), - utils.JustError(db.Exec(`INSERT INTO keys (address, json, created_at, updated_at, next_nonce, is_funding, deleted_at) VALUES ($1, '{}', NOW(), NOW(), 0, false, NOW())`, eth2)), - utils.JustError(db.Exec(`INSERT INTO encrypted_ocr_key_bundles (id, on_chain_signing_address, off_chain_public_key, encrypted_private_keys, created_at, updated_at, config_public_key, deleted_at) VALUES ($1, $2, $3, '{}', NOW(), NOW(), $4, NULL)`, ocr1, testutils.NewAddress(), utils.NewHash(), utils.NewHash())), - utils.JustError(db.Exec(`INSERT INTO encrypted_ocr_key_bundles (id, on_chain_signing_address, off_chain_public_key, encrypted_private_keys, created_at, updated_at, config_public_key, deleted_at) VALUES ($1, $2, $3, '{}', NOW(), NOW(), $4, NOW())`, ocr2, testutils.NewAddress(), utils.NewHash(), utils.NewHash())), - utils.JustError(db.Exec(`INSERT INTO encrypted_p2p_keys (peer_id, pub_key, encrypted_priv_key, created_at, updated_at, deleted_at) VALUES ($1, $2, '{}', NOW(), NOW(), NULL)`, p1.Pretty(), utils.NewHash())), - utils.JustError(db.Exec(`INSERT INTO encrypted_p2p_keys (peer_id, pub_key, encrypted_priv_key, created_at, updated_at, deleted_at) VALUES ($1, $2, '{}', NOW(), NOW(), NOW())`, p2.Pretty(), utils.NewHash())), - utils.JustError(db.Exec(`INSERT INTO encrypted_vrf_keys (public_key, vrf_key, created_at, updated_at, deleted_at) VALUES ($1, '{}', NOW(), NOW(), NULL)`, v1.PublicKey)), - utils.JustError(db.Exec(`INSERT INTO encrypted_vrf_keys (public_key, vrf_key, created_at, updated_at, deleted_at) VALUES ($1, '{}', NOW(), NOW(), NOW())`, v2.PublicKey)), - ) - require.NoError(t, err) - - t.Run("legacy functions for V1 migration", func(t *testing.T) { - t.Run("GetEncryptedV1CSAKeys", func(t *testing.T) { - ks, err := orm.GetEncryptedV1CSAKeys() - require.NoError(t, err) - assert.Len(t, ks, 1) - }) - t.Run("GetEncryptedV1EthKeys", func(t *testing.T) { - ks, err := orm.GetEncryptedV1EthKeys() - require.NoError(t, err) - assert.Len(t, ks, 1) - assert.Equal(t, eth1, ks[0].Address.Address()) - }) - t.Run("GetEncryptedV1OCRKeys", func(t *testing.T) { - ks, err := orm.GetEncryptedV1OCRKeys() - require.NoError(t, err) - assert.Len(t, ks, 1) - assert.Equal(t, ocr1.String(), hexutil.Encode(ks[0].ID[:])) - }) - t.Run("GetEncryptedV1P2PKeys", func(t *testing.T) { - ks, err := orm.GetEncryptedV1P2PKeys() - require.NoError(t, err) - assert.Len(t, ks, 1) - assert.Equal(t, p1, peer.ID(ks[0].PeerID)) - - }) - t.Run("GetEncryptedV1VRFKeys", func(t *testing.T) { - ks, err := orm.GetEncryptedV1VRFKeys() - require.NoError(t, err) - assert.Len(t, ks, 1) - assert.Equal(t, v1.PublicKey, ks[0].PublicKey) - }) - }) - -} diff --git a/core/services/keystore/p2p.go b/core/services/keystore/p2p.go index c6b21d0c1aa..657dfbc8973 100644 --- a/core/services/keystore/p2p.go +++ b/core/services/keystore/p2p.go @@ -22,8 +22,6 @@ type P2P interface { Export(id p2pkey.PeerID, password string) ([]byte, error) EnsureKey() error - GetV1KeysAsV2() ([]p2pkey.KeyV2, error) - GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) } @@ -152,21 +150,6 @@ func (ks *p2p) EnsureKey() error { return ks.safeAddKey(key) } -func (ks *p2p) GetV1KeysAsV2() (keys []p2pkey.KeyV2, _ error) { - v1Keys, err := ks.orm.GetEncryptedV1P2PKeys() - if err != nil { - return keys, err - } - for _, keyV1 := range v1Keys { - pk, err := keyV1.Decrypt(ks.password) - if err != nil { - return keys, err - } - keys = append(keys, pk.ToV2()) - } - return keys, nil -} - var ( ErrNoP2PKey = errors.New("no p2p keys exist") ) diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 07fa167a95b..63654786fd1 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -177,21 +177,4 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.NoError(t, err) require.Equal(t, "12D3KooWSq2UZgSXvhGLG5uuAAmz1JNjxHMJViJB39aorvbbYo8p", importedKey.ID()) }) - - t.Run("returns V1 keys as V2", func(t *testing.T) { - defer reset() - defer require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_p2p_keys"))) - - p1 := cltest.MustRandomP2PPeerID(t) - err := utils.JustError(db.Exec(`INSERT INTO encrypted_p2p_keys (peer_id, pub_key, encrypted_priv_key, created_at, updated_at, deleted_at) VALUES ($1, $2, '{"cipher":"aes-128-ctr","ciphertext":"adb2dff72148a8cd467f6f06a03869e7cedf180cf2a4decdb86875b2e1cf3e58c4bd2b721ecdaa88a0825fa9abfc309bf32dbb35a5c0b6cb01ac89a956d78e0550eff351","cipherparams":{"iv":"6cc4381766a4efc39f762b2b8d09dfba"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"ff5055ae4cdcdc2d0404307d578262e2caeb0210f82db3a0ecbdba727c6f5259"},"mac":"d37e4f1dea98d85960ef3205099fc71741715ae56a3b1a8f9215a78de9b95595"}', NOW(), NOW(), NULL)`, p1.Pretty(), utils.NewHash())) - require.NoError(t, err) - - keyStore.SetPassword("p4SsW0rD1!@#_") - - keys, err := ks.GetV1KeysAsV2() - require.NoError(t, err) - - assert.Len(t, keys, 1) - assert.Equal(t, fmt.Sprintf("P2PKeyV2{PrivateKey: , PeerID: %s}", keys[0].PeerID().Raw()), keys[0].GoString()) - }) } diff --git a/core/services/keystore/starknet.go b/core/services/keystore/starknet.go index 5b22d008529..7bf454004d0 100644 --- a/core/services/keystore/starknet.go +++ b/core/services/keystore/starknet.go @@ -6,6 +6,7 @@ import ( "math/big" "github.com/pkg/errors" + "github.com/smartcontractkit/caigo" "github.com/smartcontractkit/chainlink-relay/pkg/loop" @@ -13,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" ) -//go:generate mockery --name StarkNet --output ./mocks/ --case=underscore --filename starknet.go +//go:generate mockery --quiet --name StarkNet --output ./mocks/ --case=underscore --filename starknet.go type StarkNet interface { Get(id string) (starkkey.Key, error) GetAll() ([]starkkey.Key, error) diff --git a/core/services/keystore/vrf.go b/core/services/keystore/vrf.go index 30db044a566..91e77557674 100644 --- a/core/services/keystore/vrf.go +++ b/core/services/keystore/vrf.go @@ -21,8 +21,6 @@ type VRF interface { Export(id string, password string) ([]byte, error) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) - - GetV1KeysAsV2(password string) ([]vrfkey.KeyV2, error) } var ( @@ -143,24 +141,6 @@ func (ks *vrf) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) { return key.GenerateProof(seed) } -func (ks *vrf) GetV1KeysAsV2(password string) (keys []vrfkey.KeyV2, _ error) { - if len(password) == 0 { - return keys, nil - } - v1Keys, err := ks.orm.GetEncryptedV1VRFKeys() - if err != nil { - return keys, err - } - for _, keyV1 := range v1Keys { - pk, err := vrfkey.Decrypt(keyV1, password) // V1 VRF keys have their own password - if err != nil { - return keys, err - } - keys = append(keys, pk.ToV2()) - } - return keys, nil -} - func (ks *vrf) getByID(id string) (vrfkey.KeyV2, error) { key, found := ks.keyRing.VRF[id] if !found { diff --git a/core/services/keystore/vrf_test.go b/core/services/keystore/vrf_test.go index 516ca230cc2..f0c6949bbea 100644 --- a/core/services/keystore/vrf_test.go +++ b/core/services/keystore/vrf_test.go @@ -169,28 +169,4 @@ func Test_VRFKeyStore_E2E(t *testing.T) { assert.NotZero(t, pf) }) }) - - t.Run("returns V1 keys as V2", func(t *testing.T) { - defer reset() - defer require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_vrf_keys"))) - - v1 := vrfkey.MustNewV2XXXTestingOnly(big.NewInt(1)) - err := utils.JustError(db.Exec(`INSERT INTO encrypted_vrf_keys (public_key, vrf_key, created_at, updated_at, deleted_at) VALUES ($1, '{"address":"b94276ad4e5452732ec0cccf30ef7919b67844b6","crypto":{"cipher":"aes-128-ctr","ciphertext":"ff66d61d02dba54a61bab1ceb8414643f9e76b7351785d2959e2c8b50ee69a92","cipherparams":{"iv":"75705da271b11e330a27b8d593a3930c"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"efe5b372e4fe79d0af576a79d65a1ee35d0792d9c92b70107b5ada1817ea7c7b"},"mac":"e4d0bb08ffd004ab03aeaa42367acbd9bb814c6cfd981f5157503f54c30816e7"},"version": 3}', NOW(), NOW(), NULL)`, v1.PublicKey)) - require.NoError(t, err) - - t.Run("returns 0 keys passing password as empty string", func(t *testing.T) { - keys, err := ks.GetV1KeysAsV2("") - require.NoError(t, err) - - assert.Len(t, keys, 0) - }) - - t.Run("returns V1 keys as V2", func(t *testing.T) { - keys, err := ks.GetV1KeysAsV2("p4SsW0rD1!@#_") - require.NoError(t, err) - - assert.Len(t, keys, 1) - assert.Equal(t, fmt.Sprintf("VRFKeyV2{PublicKey: %s}", keys[0].PublicKey), keys[0].GoString()) - }) - }) } diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index 8a6541bba36..354812d0212 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -1,9 +1,9 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks import ( - services "github.com/smartcontractkit/chainlink/v2/core/services" + pkgservices "github.com/smartcontractkit/chainlink-relay/pkg/services" mock "github.com/stretchr/testify/mock" ) @@ -79,11 +79,11 @@ func (_m *Checker) IsReady() (bool, map[string]error) { } // Register provides a mock function with given fields: service -func (_m *Checker) Register(service services.Checkable) error { +func (_m *Checker) Register(service pkgservices.HealthReporter) error { ret := _m.Called(service) var r0 error - if rf, ok := ret.Get(0).(func(services.Checkable) error); ok { + if rf, ok := ret.Get(0).(func(pkgservices.HealthReporter) error); ok { r0 = rf(service) } else { r0 = ret.Error(0) @@ -120,13 +120,12 @@ func (_m *Checker) Unregister(name string) error { return r0 } -type mockConstructorTestingTNewChecker interface { +// NewChecker creates a new instance of Checker. 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 NewChecker(t interface { mock.TestingT Cleanup(func()) -} - -// NewChecker creates a new instance of Checker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewChecker(t mockConstructorTestingTNewChecker) *Checker { +}) *Checker { mock := &Checker{} mock.Mock.Test(t) diff --git a/core/services/multi.go b/core/services/multi.go index d12e56cfad4..4ea263f5a30 100644 --- a/core/services/multi.go +++ b/core/services/multi.go @@ -1,96 +1,27 @@ package services import ( - "context" "io" - "sync" - "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/services" ) // StartClose is a subset of the ServiceCtx interface. -type StartClose interface { - Start(context.Context) error - Close() error -} +type StartClose = services.StartClose // MultiStart is a utility for starting multiple services together. // The set of started services is tracked internally, so that they can be closed if any single service fails to start. -type MultiStart struct { - started []StartClose -} - -// Start attempts to Start all services. If any service fails to start, the previously started services will be -// Closed, and an error returned. -func (m *MultiStart) Start(ctx context.Context, srvcs ...StartClose) (err error) { - for _, s := range srvcs { - err = m.start(ctx, s) - if err != nil { - return err - } - } - return -} - -func (m *MultiStart) start(ctx context.Context, s StartClose) (err error) { - err = s.Start(ctx) - if err != nil { - err = multierr.Append(err, m.Close()) - } else { - m.started = append(m.started, s) - } - return -} - -// Close closes all started services, in reverse order. -func (m *MultiStart) Close() (err error) { - for i := len(m.started) - 1; i >= 0; i-- { - s := m.started[i] - err = multierr.Append(err, s.Close()) - } - return -} - -// CloseBecause calls Close and returns reason along with any additional errors. -func (m *MultiStart) CloseBecause(reason error) (err error) { - return multierr.Append(reason, m.Close()) -} +type MultiStart = services.MultiStart // CloseAll closes all elements concurrently. // Use this when you have various different types of io.Closer. func CloseAll(cs ...io.Closer) error { - return multiCloser[io.Closer](cs).Close() + return services.CloseAll(cs...) } // MultiCloser returns an io.Closer which closes all elements concurrently. // Use this when you have a slice of a type which implements io.Closer. // []io.Closer can be cast directly to MultiCloser. func MultiCloser[C io.Closer](cs []C) io.Closer { - return multiCloser[C](cs) -} - -type multiCloser[C io.Closer] []C - -// Close closes all elements concurrently and collects any returned errors as a multierr. -func (m multiCloser[C]) Close() (err error) { - if len(m) == 0 { - return nil - } - var wg sync.WaitGroup - wg.Add(len(m)) - errs := make(chan error, len(m)) - for _, s := range m { - go func(c io.Closer) { - defer wg.Done() - if e := c.Close(); e != nil { - errs <- e - } - }(s) - } - wg.Wait() - close(errs) - for e := range errs { - err = multierr.Append(err, e) - } - return + return services.MultiCloser(cs) } diff --git a/core/services/multi_example_test.go b/core/services/multi_example_test.go deleted file mode 100644 index 235e1615852..00000000000 --- a/core/services/multi_example_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package services - -import ( - "context" - "fmt" -) - -type Healthy string - -func (h Healthy) Start(ctx context.Context) error { - fmt.Println(h, "started") - return nil -} - -func (h Healthy) Close() error { - fmt.Println(h, "closed") - return nil -} - -type CloseFailure string - -func (c CloseFailure) Start(ctx context.Context) error { - fmt.Println(c, "started") - return nil -} - -func (c CloseFailure) Close() error { - fmt.Println(c, "close failure") - return fmt.Errorf("failed to close: %s", c) -} - -type WontStart string - -func (f WontStart) Start(ctx context.Context) error { - fmt.Println(f, "start failure") - return fmt.Errorf("failed to start: %s", f) -} - -func (f WontStart) Close() error { - fmt.Println(f, "close failure") - return fmt.Errorf("cannot call Close after failed Start: %s", f) -} - -func ExampleMultiStart() { - ctx := context.Background() - - a := Healthy("a") - b := CloseFailure("b") - c := WontStart("c") - - var ms MultiStart - if err := ms.Start(ctx, a, b, c); err != nil { - fmt.Println(err) - } - - // Output: - // a started - // b started - // c start failure - // b close failure - // a closed - // failed to start: c; failed to close: b -} - -func ExampleMultiCloser() { - ctx := context.Background() - - f1 := CloseFailure("f") - f2 := CloseFailure("f") - cs := []CloseFailure{f1, f2} - - var ms MultiStart - if err := ms.Start(ctx, f1, f2); err != nil { - fmt.Println(err) - return - } - mc := MultiCloser(cs) - if err := mc.Close(); err != nil { - fmt.Println(err) - } - - // Output: - // f started - // f started - // f close failure - // f close failure - // failed to close: f; failed to close: f -} diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 0c7e288bd43..a7df28e1c76 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -13,6 +13,7 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" + "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" @@ -399,7 +400,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight // care about the block height; we have no way of getting the L1 block // height anyway return 0, nil - case "", config.ChainArbitrum, config.ChainXDai: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 9ed22d01e72..dee349a9a0d 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -87,7 +87,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec returns the OCR services that need to run for this job -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { if jb.OCROracleSpec == nil { return nil, errors.Errorf("offchainreporting.Delegate expects an *job.OffchainreportingOracleSpec to be present, got %v", jb) } @@ -297,7 +297,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.EnhancedEA, "EVM", chain.ID().String()), lggr.Named("EnhancedTelemetry")) services = append(services, enhancedTelemService) } @@ -319,7 +319,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job Logger: ocrLogger, V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.OCR), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String(), synchronization.OCR, "EVM", chain.ID().String()), ConfigOverrider: configOverrider, }) if err != nil { diff --git a/core/services/ocr/mocks/ocr_contract_tracker_db.go b/core/services/ocr/mocks/ocr_contract_tracker_db.go index b48ec50cc7f..a1d2f523ccb 100644 --- a/core/services/ocr/mocks/ocr_contract_tracker_db.go +++ b/core/services/ocr/mocks/ocr_contract_tracker_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -53,13 +53,12 @@ func (_m *OCRContractTrackerDB) SaveLatestRoundRequested(tx pg.Queryer, rr offch return r0 } -type mockConstructorTestingTNewOCRContractTrackerDB interface { +// NewOCRContractTrackerDB creates a new instance of OCRContractTrackerDB. 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 NewOCRContractTrackerDB(t interface { mock.TestingT Cleanup(func()) -} - -// NewOCRContractTrackerDB creates a new instance of OCRContractTrackerDB. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewOCRContractTrackerDB(t mockConstructorTestingTNewOCRContractTrackerDB) *OCRContractTrackerDB { +}) *OCRContractTrackerDB { mock := &OCRContractTrackerDB{} mock.Mock.Test(t) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 2086eaa6a80..ef1ae7c5888 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -92,7 +92,6 @@ type Delegate struct { RelayGetter isNewlyCreatedJob bool // Set to true if this is a new job freshly added, false if job was present already on node boot. mailMon *utils.MailboxMonitor - eventBroadcaster pg.EventBroadcaster legacyChains evm.LegacyChainContainer // legacy: use relayers instead } @@ -213,7 +212,7 @@ func NewDelegate( monitoringEndpointGen: monitoringEndpointGen, legacyChains: legacyChains, cfg: cfg, - lggr: lggr, + lggr: lggr.Named("OCR2"), ks: ks, dkgSignKs: dkgSignKs, dkgEncryptKs: dkgEncryptKs, @@ -221,7 +220,6 @@ func NewDelegate( RelayGetter: relayers, isNewlyCreatedJob: false, mailMon: mailMon, - eventBroadcaster: eventBroadcaster, } } @@ -315,7 +313,7 @@ func (d *Delegate) cleanupEVM(jb job.Job, q pg.Queryer, relayID relay.ID) error } // ServicesForSpec returns the OCR2 services that need to run for this job -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { spec := jb.OCR2OracleSpec if spec == nil { return nil, errors.Errorf("offchainreporting2.Delegate expects an *job.OCR2OracleSpec to be present, got %v", jb) @@ -335,7 +333,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC lggrCtx.FeedID = *spec.FeedID spec.RelayConfig["feedID"] = spec.FeedID } - lggr := logger.Sugared(d.lggr.Named("OCR2").With(lggrCtx.Args()...)) + lggr := logger.Sugared(d.lggr.Named(jb.ExternalJobID.String()).With(lggrCtx.Args()...)) rid, err := spec.RelayID() if err != nil { @@ -543,7 +541,7 @@ func (d *Delegate) newServicesMercury( Database: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.OCR3Mercury), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.OCR3Mercury, rid.Network, rid.ChainID), OffchainConfigDigester: mercuryProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -554,7 +552,7 @@ func (d *Delegate) newServicesMercury( mercuryServices, err2 := mercury.NewServices(jb, mercuryProvider, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, d.cfg.JobPipeline(), chEnhancedTelem, chain, d.mercuryORM, (mercuryutils.FeedID)(*spec.FeedID)) if ocrcommon.ShouldCollectEnhancedTelemetryMercury(&jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.EnhancedEAMercury), lggr.Named("EnhancedTelemetryMercury")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, chEnhancedTelem, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.FeedID.String(), synchronization.EnhancedEAMercury, rid.Network, rid.ChainID), lggr.Named("EnhancedTelemetryMercury")) mercuryServices = append(mercuryServices, enhancedTelemService) } @@ -573,13 +571,19 @@ func (d *Delegate) newServicesMedian( ocrLogger commontypes.Logger, ) ([]job.ServiceCtx, error) { spec := jb.OCR2OracleSpec + + rid, err := spec.RelayID() + if err != nil { + return nil, fmt.Errorf("median services: %w: %w", ErrJobSpecNoRelayer, err) + } + oracleArgsNoPlugin := libocr2.OCR2OracleArgs{ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, V2Bootstrappers: bootstrapPeers, Database: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Median), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Median, rid.Network, rid.ChainID), OffchainKeyring: kb, OnchainKeyring: kb, } @@ -587,10 +591,6 @@ func (d *Delegate) newServicesMedian( enhancedTelemChan := make(chan ocrcommon.EnhancedTelemetryData, 100) mConfig := median.NewMedianConfig(d.cfg.JobPipeline().MaxSuccessfulRuns(), d.cfg) - rid, err := spec.RelayID() - if err != nil { - return nil, fmt.Errorf("median services: %w: %w", ErrJobSpecNoRelayer, err) - } relayer, err := d.RelayGetter.Get(rid) if err != nil { return nil, fmt.Errorf("median services; failed to get relay %s is it enabled?: %w", spec.Relay, err) @@ -599,7 +599,7 @@ func (d *Delegate) newServicesMedian( medianServices, err2 := median.NewMedianServices(ctx, jb, d.isNewlyCreatedJob, relayer, d.pipelineRunner, runResults, lggr, oracleArgsNoPlugin, mConfig, enhancedTelemChan, errorLog) if ocrcommon.ShouldCollectEnhancedTelemetry(&jb) { - enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.EnhancedEA), lggr.Named("EnhancedTelemetry")) + enhancedTelemService := ocrcommon.NewEnhancedTelemetryService(&jb, enhancedTelemChan, make(chan struct{}), d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.EnhancedEA, rid.Network, rid.ChainID), lggr.Named("EnhancedTelemetry")) medianServices = append(medianServices, enhancedTelemService) } @@ -820,7 +820,7 @@ func (d *Delegate) newServicesOCR2VRF( VRFContractTransmitter: vrfProvider.ContractTransmitter(), VRFDatabase: ocrDB, VRFLocalConfig: lc, - VRFMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2VRF), + VRFMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2VRF, rid.Network, rid.ChainID), DKGContractConfigTracker: dkgProvider.ContractConfigTracker(), DKGOffchainConfigDigester: dkgProvider.OffchainConfigDigester(), DKGContract: dkgpkg.NewOnchainContract(dkgContract, &altbn_128.G2{}), @@ -959,7 +959,7 @@ func (d *Delegate) newServicesOCR2Keepers21( ContractConfigTracker: keeperProvider.ContractConfigTracker(), KeepersDatabase: ocrDB, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation, rid.Network, rid.ChainID), OffchainConfigDigester: keeperProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: services.Keyring(), @@ -1104,7 +1104,7 @@ func (d *Delegate) newServicesOCR2Keepers20( KeepersDatabase: ocrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Automation, rid.Network, rid.ChainID), OffchainConfigDigester: keeperProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -1213,7 +1213,7 @@ func (d *Delegate) newServicesOCR2Functions( Database: functionsOcrDB, LocalConfig: lc, Logger: ocrLogger, - MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Functions), + MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.OCR2Functions, rid.Network, rid.ChainID), OffchainConfigDigester: functionsProvider.OffchainConfigDigester(), OffchainKeyring: kb, OnchainKeyring: kb, @@ -1277,7 +1277,7 @@ func (d *Delegate) newServicesOCR2Functions( ContractID: spec.ContractID, Logger: lggr, MailMon: d.mailMon, - URLsMonEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.FunctionsRequests), + URLsMonEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(spec.ContractID, synchronization.FunctionsRequests, rid.Network, rid.ChainID), EthKeystore: d.ethKs, ThresholdKeyShare: thresholdKeyShare, LogPollerWrapper: functionsProvider.LogPollerWrapper(), diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index 97c9faa44d4..3973774c56a 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -136,7 +136,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { } t.Run("when sending keys are not defined, the first one should be set to transmitterID", func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) jb.OCR2OracleSpec.TransmitterID = null.StringFrom("some transmitterID string") jb.OCR2OracleSpec.RelayConfig["sendingKeys"] = nil @@ -150,7 +150,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) setTestCase(&jb, tc, txManager) chain, err := legacyChains.Get(customChainID.String()) @@ -173,7 +173,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { } t.Run("when forwarders are enabled and chain retrieval fails, error should be handled", func(t *testing.T) { - jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) + jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.GetOCR2EVMSpecMinimal()) require.NoError(t, err) jb.ForwardingAllowed = true jb.OCR2OracleSpec.TransmitterID = null.StringFrom("0x7e57000000000000000000000000000000000001") diff --git a/core/services/ocr2/plugins/functions/encoding/abi_codec.go b/core/services/ocr2/plugins/functions/encoding/abi_codec.go index e7f62605db9..bbf624d4b29 100644 --- a/core/services/ocr2/plugins/functions/encoding/abi_codec.go +++ b/core/services/ocr2/plugins/functions/encoding/abi_codec.go @@ -12,22 +12,12 @@ type ReportCodec interface { DecodeReport(raw []byte) ([]*ProcessedRequest, error) } -type reportCodecV0 struct { - reportTypes abi.Arguments -} - type reportCodecV1 struct { reportTypes abi.Arguments } func NewReportCodec(contractVersion uint32) (ReportCodec, error) { switch contractVersion { - case 0: // deprecated - reportTypes, err := getReportTypesV0() - if err != nil { - return nil, err - } - return &reportCodecV0{reportTypes: reportTypes}, nil case 1: reportTypes, err := getReportTypesV1() if err != nil { @@ -48,81 +38,6 @@ func SliceToByte32(slice []byte) ([32]byte, error) { return res, nil } -func getReportTypesV0() (abi.Arguments, error) { - bytes32ArrType, err := abi.NewType("bytes32[]", "", []abi.ArgumentMarshaling{}) - if err != nil { - return nil, fmt.Errorf("unable to create an ABI type object for bytes32[]") - } - bytesArrType, err := abi.NewType("bytes[]", "", []abi.ArgumentMarshaling{}) - if err != nil { - return nil, fmt.Errorf("unable to create an ABI type object for bytes[]") - } - return abi.Arguments([]abi.Argument{ - {Name: "ids", Type: bytes32ArrType}, - {Name: "results", Type: bytesArrType}, - {Name: "errors", Type: bytesArrType}, - }), nil -} - -func (c *reportCodecV0) EncodeReport(requests []*ProcessedRequest) ([]byte, error) { - size := len(requests) - if size == 0 { - return []byte{}, nil - } - ids := make([][32]byte, size) - results := make([][]byte, size) - errors := make([][]byte, size) - for i := 0; i < size; i++ { - var err error - ids[i], err = SliceToByte32(requests[i].RequestID) - if err != nil { - return nil, err - } - results[i] = requests[i].Result - errors[i] = requests[i].Error - } - return c.reportTypes.Pack(ids, results, errors) -} - -func (c *reportCodecV0) DecodeReport(raw []byte) ([]*ProcessedRequest, error) { - reportElems := map[string]interface{}{} - if err := c.reportTypes.UnpackIntoMap(reportElems, raw); err != nil { - return nil, errors.WithMessage(err, "unable to unpack elements from raw report") - } - - idsIface, idsOK := reportElems["ids"] - resultsIface, resultsOK := reportElems["results"] - errorsIface, errorsOK := reportElems["errors"] - if !idsOK || !resultsOK || !errorsOK { - return nil, fmt.Errorf("missing arrays in raw report, ids: %v, results: %v, errors: %v", idsOK, resultsOK, errorsOK) - } - - ids, idsOK := idsIface.([][32]byte) - results, resultsOK := resultsIface.([][]byte) - errors, errorsOK := errorsIface.([][]byte) - if !idsOK || !resultsOK || !errorsOK { - return nil, fmt.Errorf("unable to cast part of raw report into array type, ids: %v, results: %v, errors: %v", idsOK, resultsOK, errorsOK) - } - - size := len(ids) - if len(results) != size || len(errors) != size { - return nil, fmt.Errorf("unequal sizes of arrays parsed from raw report, ids: %v, results: %v, errors: %v", len(ids), len(results), len(errors)) - } - if size == 0 { - return []*ProcessedRequest{}, nil - } - - decoded := make([]*ProcessedRequest, size) - for i := 0; i < size; i++ { - decoded[i] = &ProcessedRequest{ - RequestID: ids[i][:], - Result: results[i], - Error: errors[i], - } - } - return decoded, nil -} - func getReportTypesV1() (abi.Arguments, error) { bytes32ArrType, err := abi.NewType("bytes32[]", "", []abi.ArgumentMarshaling{}) if err != nil { diff --git a/core/services/ocr2/plugins/functions/encoding/abi_codec_test.go b/core/services/ocr2/plugins/functions/encoding/abi_codec_test.go index 03c8b87af16..d20534a656c 100644 --- a/core/services/ocr2/plugins/functions/encoding/abi_codec_test.go +++ b/core/services/ocr2/plugins/functions/encoding/abi_codec_test.go @@ -9,37 +9,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" ) -func TestABICodec_EncodeDecodeV0Success(t *testing.T) { - t.Parallel() - codec, err := encoding.NewReportCodec(0) - require.NoError(t, err) - - var report = []*encoding.ProcessedRequest{ - { - RequestID: []byte(fmt.Sprintf("%032d", 123)), - Result: []byte("abcd"), - Error: []byte("err string"), - }, - { - RequestID: []byte(fmt.Sprintf("%032d", 4321)), - Result: []byte("0xababababab"), - Error: []byte(""), - }, - } - - encoded, err := codec.EncodeReport(report) - require.NoError(t, err) - decoded, err := codec.DecodeReport(encoded) - require.NoError(t, err) - - require.Equal(t, len(report), len(decoded)) - for i := 0; i < len(report); i++ { - require.Equal(t, report[i].RequestID, decoded[i].RequestID, "RequestIDs not equal at index %d", i) - require.Equal(t, report[i].Result, decoded[i].Result, "Results not equal at index %d", i) - require.Equal(t, report[i].Error, decoded[i].Error, "Errors not equal at index %d", i) - } -} - func TestABICodec_EncodeDecodeV1Success(t *testing.T) { t.Parallel() codec, err := encoding.NewReportCodec(1) diff --git a/core/services/ocr2/plugins/functions/integration_tests/v0/functions_integration_test.go b/core/services/ocr2/plugins/functions/integration_tests/v0/functions_integration_test.go deleted file mode 100644 index 011e67c77ca..00000000000 --- a/core/services/ocr2/plugins/functions/integration_tests/v0/functions_integration_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package functions_test - -import ( - "testing" - "time" - - functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - utils "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/integration_tests/v0/internal" -) - -var ( - // a batch of 8 max-length results uses around 1M gas (assuming 70k gas per client callback - see FunctionsClientExample.sol) - nOracleNodes = 4 - nClients = 50 - requestLenBytes = 1000 - maxGas = 1_300_000 - batchSize = 8 -) - -func TestIntegration_Functions_MultipleRequests_Success(t *testing.T) { - // simulated chain with all contracts - owner, b, ticker, oracleContractAddress, oracleContract, clientContracts, registryAddress, registryContract, linkToken := utils.StartNewChainWithContracts(t, nClients) - defer ticker.Stop() - - _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, oracleContractAddress, nOracleNodes, maxGas, nil, nil) - - // config for registry contract - utils.SetRegistryConfig(t, owner, registryContract, oracleContractAddress) - - pluginConfig := functionsConfig.ReportingPluginConfig{ - MaxQueryLengthBytes: 10_000, - MaxObservationLengthBytes: 10_000, - MaxReportLengthBytes: 15_000, - MaxRequestBatchSize: uint32(batchSize), - DefaultAggregationMethod: functionsConfig.AggregationMethod_AGGREGATION_MODE, - UniqueReports: true, - } - - // config for oracle contract - utils.SetOracleConfig(t, owner, oracleContract, oracleIdentities, batchSize, &pluginConfig) - utils.CommitWithFinality(b) - - // validate that all client contracts got correct responses to their requests - utils.ClientTestRequests(t, owner, b, linkToken, registryAddress, registryContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, 1*time.Minute) -} - -func TestIntegration_Functions_MultipleRequests_ThresholdDecryptionSuccess(t *testing.T) { - // simulated chain with all contracts - owner, b, ticker, oracleContractAddress, oracleContract, clientContracts, registryAddress, registryContract, linkToken := utils.StartNewChainWithContracts(t, nClients) - defer ticker.Stop() - - _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, oracleContractAddress, nOracleNodes, maxGas, utils.ExportedOcr2Keystores, utils.MockThresholdKeyShares) - - // config for registry contract - utils.SetRegistryConfig(t, owner, registryContract, oracleContractAddress) - - pluginConfig := functionsConfig.ReportingPluginConfig{ - MaxQueryLengthBytes: 10_000, - MaxObservationLengthBytes: 10_000, - MaxReportLengthBytes: 15_000, - MaxRequestBatchSize: uint32(batchSize), - DefaultAggregationMethod: functionsConfig.AggregationMethod_AGGREGATION_MODE, - UniqueReports: true, - ThresholdPluginConfig: &functionsConfig.ThresholdReportingPluginConfig{ - // approximately 750 bytes per test ciphertext + overhead - MaxQueryLengthBytes: 70_000, - MaxObservationLengthBytes: 70_000, - MaxReportLengthBytes: 70_000, - RequestCountLimit: 50, - RequestTotalBytesLimit: 50_000, - RequireLocalRequestCheck: true, - K: 2, - }, - } - - // config for oracle contract - utils.SetOracleConfig(t, owner, oracleContract, oracleIdentities, batchSize, &pluginConfig) - utils.CommitWithFinality(b) - - // validate that all client contracts got correct responses to their requests - utils.ClientTestRequests(t, owner, b, linkToken, registryAddress, registryContract, clientContracts, requestLenBytes, utils.DefaultSecretsUrlsBytes, 1*time.Minute) -} diff --git a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testconstants.go b/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testconstants.go deleted file mode 100644 index 62de14febfc..00000000000 --- a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testconstants.go +++ /dev/null @@ -1,37 +0,0 @@ -package testutils - -var ( - DefaultSecretsBytes = []byte{0xaa, 0xbb, 0xcc} - DefaultSecretsBase64 = "qrvM" - DefaultSecretsUrlsBytes = []byte{0x01, 0x02, 0x03} - DefaultSecretsUrlsBase64 = "AQID" - DefaultArg1 = "arg1" - DefaultArg2 = "arg2" - DefaultGasPrice = 1_000_000_000 - - // Below are the corresponding values for the encrypted threshold keys used in the test - // mockThresholdPubKey := `{"Group":"P256","G_bar":"BAnzIguQNKnA37Zh0b3Z3K5CcvxHjzfTIytt37ZgNQLaTeuiq9rrVhz+yaZcvNQ9EYw978KmmYOq6qd0NA/ERh8=","H":"BOyfKc8aowVjOK2qYf0kdeuLkPeqbjDnjDFGIj/2n7O+qHIvqKx3A07Oa92tP5DkcS5AL/tipXDIBJvVWvcvudk=","HArray":["BBhLQicdsIUgigmIW4l6Xi1jBkFFXEtm2wuvydoZCjZZdlDZt82pXtOI+vPQbd5iawQPX6u4HUrhEisqwhx5P0A=","BLTOIUViwoVJTAzCKIo2FgliIfK7w3jG6wjwf3LVkdsMYJ2ZiEJDA7YC1GwsVgutYdxrwOkAY+wnoh9j+AYF/rQ=","BH2vi5G9ftykpOJARMlziZuZKXSx5YiP131HpwWwsgFAquSpsNTRWHsjk4nc0lcQKf6x9E+7UUQpAPwDpyrh7Xc=","BHQBZMqVRvxQHtnC4tqfh9Qc632IfSCPCBDsePyLzD1nXOf/qJWrCpfsZ3T3PaRm/U30LSgnb1nsuXI9nDuTFsM="]}` - // mockPlaintextThresholdMasterKey := `{"Group":"P256","S":"MTpFRrh8F5mih+92W0l51ZVZIiGJgpHNUXb4vzkzv8A="}` - // mockPlaintextThresholdKeyShares := [][]byte{ - // []byte(`{"PublicKey":{"Group":"P256","G_bar":"BAnzIguQNKnA37Zh0b3Z3K5CcvxHjzfTIytt37ZgNQLaTeuiq9rrVhz+yaZcvNQ9EYw978KmmYOq6qd0NA/ERh8=","H":"BOyfKc8aowVjOK2qYf0kdeuLkPeqbjDnjDFGIj/2n7O+qHIvqKx3A07Oa92tP5DkcS5AL/tipXDIBJvVWvcvudk=","HArray":["BBhLQicdsIUgigmIW4l6Xi1jBkFFXEtm2wuvydoZCjZZdlDZt82pXtOI+vPQbd5iawQPX6u4HUrhEisqwhx5P0A=","BLTOIUViwoVJTAzCKIo2FgliIfK7w3jG6wjwf3LVkdsMYJ2ZiEJDA7YC1GwsVgutYdxrwOkAY+wnoh9j+AYF/rQ=","BH2vi5G9ftykpOJARMlziZuZKXSx5YiP131HpwWwsgFAquSpsNTRWHsjk4nc0lcQKf6x9E+7UUQpAPwDpyrh7Xc=","BHQBZMqVRvxQHtnC4tqfh9Qc632IfSCPCBDsePyLzD1nXOf/qJWrCpfsZ3T3PaRm/U30LSgnb1nsuXI9nDuTFsM="]},"PrivateKeyShare":{"Group":"P256","Index":0,"V":"Jzuh+h/jgm0HIp6iKVJxc/vCUOz7Ea+Y0twvRzJDheg="}}`), - // []byte(`{"PublicKey":{"Group":"P256","G_bar":"BAnzIguQNKnA37Zh0b3Z3K5CcvxHjzfTIytt37ZgNQLaTeuiq9rrVhz+yaZcvNQ9EYw978KmmYOq6qd0NA/ERh8=","H":"BOyfKc8aowVjOK2qYf0kdeuLkPeqbjDnjDFGIj/2n7O+qHIvqKx3A07Oa92tP5DkcS5AL/tipXDIBJvVWvcvudk=","HArray":["BBhLQicdsIUgigmIW4l6Xi1jBkFFXEtm2wuvydoZCjZZdlDZt82pXtOI+vPQbd5iawQPX6u4HUrhEisqwhx5P0A=","BLTOIUViwoVJTAzCKIo2FgliIfK7w3jG6wjwf3LVkdsMYJ2ZiEJDA7YC1GwsVgutYdxrwOkAY+wnoh9j+AYF/rQ=","BH2vi5G9ftykpOJARMlziZuZKXSx5YiP131HpwWwsgFAquSpsNTRWHsjk4nc0lcQKf6x9E+7UUQpAPwDpyrh7Xc=","BHQBZMqVRvxQHtnC4tqfh9Qc632IfSCPCBDsePyLzD1nXOf/qJWrCpfsZ3T3PaRm/U30LSgnb1nsuXI9nDuTFsM="]},"PrivateKeyShare":{"Group":"P256","Index":1,"V":"HTz+rYdK7UBrvU3N91tpEmIrf7hsoM1kVEFlzytTTBA="}}`), - // []byte(`{"PublicKey":{"Group":"P256","G_bar":"BAnzIguQNKnA37Zh0b3Z3K5CcvxHjzfTIytt37ZgNQLaTeuiq9rrVhz+yaZcvNQ9EYw978KmmYOq6qd0NA/ERh8=","H":"BOyfKc8aowVjOK2qYf0kdeuLkPeqbjDnjDFGIj/2n7O+qHIvqKx3A07Oa92tP5DkcS5AL/tipXDIBJvVWvcvudk=","HArray":["BBhLQicdsIUgigmIW4l6Xi1jBkFFXEtm2wuvydoZCjZZdlDZt82pXtOI+vPQbd5iawQPX6u4HUrhEisqwhx5P0A=","BLTOIUViwoVJTAzCKIo2FgliIfK7w3jG6wjwf3LVkdsMYJ2ZiEJDA7YC1GwsVgutYdxrwOkAY+wnoh9j+AYF/rQ=","BH2vi5G9ftykpOJARMlziZuZKXSx5YiP131HpwWwsgFAquSpsNTRWHsjk4nc0lcQKf6x9E+7UUQpAPwDpyrh7Xc=","BHQBZMqVRvxQHtnC4tqfh9Qc632IfSCPCBDsePyLzD1nXOf/qJWrCpfsZ3T3PaRm/U30LSgnb1nsuXI9nDuTFsM="]},"PrivateKeyShare":{"Group":"P256","Index":2,"V":"Ez5bYO6yWBPQV/z5xWRgsMiUroPeL+sv1aacVyRjEjg="}}`), - // []byte(`{"PublicKey":{"Group":"P256","G_bar":"BAnzIguQNKnA37Zh0b3Z3K5CcvxHjzfTIytt37ZgNQLaTeuiq9rrVhz+yaZcvNQ9EYw978KmmYOq6qd0NA/ERh8=","H":"BOyfKc8aowVjOK2qYf0kdeuLkPeqbjDnjDFGIj/2n7O+qHIvqKx3A07Oa92tP5DkcS5AL/tipXDIBJvVWvcvudk=","HArray":["BBhLQicdsIUgigmIW4l6Xi1jBkFFXEtm2wuvydoZCjZZdlDZt82pXtOI+vPQbd5iawQPX6u4HUrhEisqwhx5P0A=","BLTOIUViwoVJTAzCKIo2FgliIfK7w3jG6wjwf3LVkdsMYJ2ZiEJDA7YC1GwsVgutYdxrwOkAY+wnoh9j+AYF/rQ=","BH2vi5G9ftykpOJARMlziZuZKXSx5YiP131HpwWwsgFAquSpsNTRWHsjk4nc0lcQKf6x9E+7UUQpAPwDpyrh7Xc=","BHQBZMqVRvxQHtnC4tqfh9Qc632IfSCPCBDsePyLzD1nXOf/qJWrCpfsZ3T3PaRm/U30LSgnb1nsuXI9nDuTFsM="]},"PrivateKeyShare":{"Group":"P256","Index":3,"V":"CT+4FFYZwuc08qwlk21YTy793U9Pvwj7VwvS3x1y2GA="}}`), - // } - // Since the threshold public keys are encrypted with each node's public OCR2 offchain config key, the OCR2 offchain config key must be known in advance instead of regenerated every time. - ExportedOcr2Keystores = [][]byte{ - []byte(`{"keyType":"OCR2","chainType":"evm","id":"d8d0363c218526d809b8570257e7822bfde559ed532fa976118fc2d994155e55","onchainPublicKey":"e1deb8516367e7715da19134d58528778d6aff04","offchainPublicKey":"91c021d592ae5949eafaf4b74d622b13ac5784db7de9591755c3d3d2ed7a19b4","configPublicKey":"677c7ba4487eabea0f3341a095b94b6f56a1df97a165e49b8b0a7864c0f66077","crypto":{"cipher":"aes-128-ctr","ciphertext":"6d111479822c5b6e5a2b5ebde4f7ab6e6f7809e07bf6451d416f5e3082833a3b34e9aa820658c03487a3bdde5cbbfff3198a951f36a5ef91d1274211273f7af2e3e17e258530c25aebb1099395ecc1d96e567adefa727f06fcb61d0df2829737998bdd959759c62342fbd74a3f231535bb413d9c4479e33ff294d66bfc90d2b6db9d12250ef8daab309bb914373a76da24e82dce5b0da428a19efc1cdda48719f898a91f21b4fc89458d126d1023ffc0efcc8cf3e0ee249bfa0b1b55fa151d5c2630be21be2ea27964b82816ee72885f7bc59d7d4157d5333ab8324cc65a78581437a8600e8c044fabe80ae76cbe39ae332c5c0f85ac1090b13a1525caca40459082e9ca762714e50543e6aa907b7286eafc93a51c2d67265393d86ad83d431bf068aa006c36f63356","cipherparams":{"iv":"11b7b2f3c33dfff2a3125fdb10048601"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"a3c5952aa41720097a50fea6957c994a9c39cb1dbe7bd59cff5b9354633836c1"},"mac":"df6d0d0b5f2cc95f1e1d4c9894f8487c56b814ca55d10e520d0c44e91d699012"}}`), - []byte(`{"keyType":"OCR2","chainType":"evm","id":"03a0713ffb5b506cbf12bd59fd7023c9dc3f1f56d4d2f9ed564f0361c3aa1119","onchainPublicKey":"3203c6923adc7ecff671e00632eb350fa354e957","offchainPublicKey":"c9aea40c0e5f13d9704d3051faa01718f1d4aa1419d3e6199f7deacee56a596e","configPublicKey":"23ccc8500fa3af447c7a8b3aa4e41ad7b34f6585bdc3e8c847c7ff12a8caa818","crypto":{"cipher":"aes-128-ctr","ciphertext":"5aa58bfd17209a4c9da966a1b175c74137536531ada19507434d6dbf146d71516c0ed2b52b5e664e69c4286a56f38be322206a33eacfaa854be313bade3b5876e5b40aec5be4dca761749b535ad9cd1575897d6736eb96fb9e118eb696c44d111b81757bd73a6d33c170febaf57705590f279625ec536d1656eac96a953de915693a9cd040a5d5948f3b288ebdbb178c955b5f0faa432d68e744f39dc621cbc4c5853627addc3dd2ed5e1ba4a514278d56d0cdef2e57688ad0752f3077656f16fa3144c33f3ed96ebdeb3009139f327d6c12d344a047147e71a95d5b08582bd8ee86c86e308d81f16357c79b50a48041994d98490a4b9d965525187901a2862d41bcc6822046f99ad481ae104aa75b816c5abac876bce0b07b2b73bb459830a5bc70f20c34b87ed6fc","cipherparams":{"iv":"d8fcf50fff54dfa082d40c0de90b6ab4"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"64ba7faf39b49c46d5360109ef23e3f4198a3f402cbb975686fe4b52cc7c0b1f"},"mac":"09520656cc08b5743f95d386a5b7c3d164ecaa2002a0b83f2cd8d44c97d99b8a"}}`), - []byte(`{"keyType":"OCR2","chainType":"evm","id":"ace8972c126601fdc5f9ed42c909a57d2a19dff2be7ce341913c01a4921c829f","onchainPublicKey":"d8699a99d2a3ab4ccfc61bc7df72b30605a05b7c","offchainPublicKey":"9c1fa3ce9d355a73ce2dcdece70e7314af8da13f5ca30ee251dbed201dc904ed","configPublicKey":"9a2b9087af305c187d1292842072e50d2c4e98cb4e26c6328021fdd992e78926","crypto":{"cipher":"aes-128-ctr","ciphertext":"c7d2da9c60779ad33dce870b1f8af94082dfdfe51d4f04f27cf505bba21b17e287c685880614e22df92ce7549230e8b1a327de0686d892f5c4dda546132b044bde2a58d60bf335931b78e42342e2578e54111592cad4301d22c192c87809e3cef6e6dd1a30a7a208c78461154d856213466c1afad4023001c1b45fdf7804c6a9a4eb64ac1ea59775a1e694c79fc492b4d7422cd777778549c817e735e8e5e5f45aea9c9e9a5a7ff1c71b7879af120a4aa467a3ac0cdb1ba04f893283cad533c4ac9723969a64bbfd69bb7ef88d88d8d96c5293fee35c14a00a8e6c0cb2e7cfa918d05ec9e092e4fdad2a41edf7a1cb9e1a1a12ec6fbb594eb1e07d5dbb79eda390b826aa7ca8ccfda1cee9c125eb8a1d07d9e899cf6e9c1ec0fd40d83a50656674cc5c9d0a88710c65","cipherparams":{"iv":"5b6fca38ff8c03e38fb6f56f9d90fe8d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"6bfc5f03e8bd10efea3808d025c5769a49ade8bee6c608d713a6bf3f940a37ba"},"mac":"e1e4bcbe67a80d73ee12c8080ddd99bba9ca8774349a9cb5c5b9821983e460ca"}}`), - []byte(`{"keyType":"OCR2","chainType":"evm","id":"5b09af3b5a5a420436fa206eb266b6a4d796406030d022d4beaf6609e9da9274","onchainPublicKey":"c27e7957c243e061cc17d8f30e8f894280235499","offchainPublicKey":"f6c2fd84bb73252d49852b50420f5983b488609d9f73ef601e7641df24794dec","configPublicKey":"45a96a32b7339cd22da1a1c42c2ee71e698dd7dfbe7fd997949f1cdb3f2ba518","crypto":{"cipher":"aes-128-ctr","ciphertext":"f842a872d8a0033fc9b91673a1c2f095eda18c4716b53c743d04b82710f2bfa2c950356e50ea085b05975c36176a3dd2b10901508f297e3ff966cde02cf6ba077eebdb8708117c4c9f4498358e74fdc98bc1130a32bfa6bf8f46d9ea77d4e56952cc1ccbbf2bde05a48acf13fbb238675d640b6a74af70dfbaa63cad57108480238ce946a5af5f60b09794ff5b40bde982f32d7b48f5e9a51830a46cce1cf2f9a0c0ec220c062eb90602b2abbaf2a6a2da2d8b3dbc211db17d599789654a2a26f1fad52e22d7eed91365ce7d964731936307c39e66bd9a9ffc999f3174317786077ab83224d06e025b7de5974293b96eabcb3b9ffb17d2d0b49743cd7b4f1b222e32be3f32b9d2177b1c20cb7d56c10ae0789f8586ee99ccd9ac8b626df058b454686b2d8a663635b8","cipherparams":{"iv":"21a5417a99f37507bc2fbdda83c5856f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":2,"p":1,"r":8,"salt":"c98ac207e897658d7c42029c2858ba29f03abe9298745b0b909377085806895a"},"mac":"dc1ef1c284e1d001b63f1d545e308c4ef194757605a4b57b8c565c5c40e64146"}}`), - } - // Threshold key shares have been generated with the Functions admin tooling (https://github.com/smartcontractkit/functions-admin-tooling/tree/main/threshold_key_manager) - MockThresholdKeyShares = []string{ - "40e99151aaa2002631cfdac741a0f206b9ebc492a2c5bd56deac64118148df6e3829a6f81b6df54694ca241f5bc12fd2b58bce9106767f4adbf7250e0a033386b56eb93159c3cf14748b6a0d1996a51039ce9ff98acaba758913fa2d671e86b909edbe27bdf441b68be2c2debbe8a29d814a04accd996b4df0fa8e0cea65ef47922c4aca8132fe4f2d6def9c4683b031267f60ccf896b6bf6b1957786deafebb5bc1663778ee893511306dda7833d01efe0d63224d0da0cea6d728953793e6b3e97f81cb64f80ed4ff4f3c349b90f11290adb0eff07f8ccb9b97d098903ce194f33f284d38832e12902354c3cda72189b3ac31b8206575391c1618dee6530b99fc60d667052e0065365842176b6b5d9b779be0be4f7fa27115d65e08d01f13db695581c1be4a1f96b980cba45bd528aaee23809fa9a601a229c7018eb6755f43a0d38125a872fcf8e109ca92abc55348cccc4f83beae8412425570b8aa9b6526a9ddd05a41e5c6d6865cf91ff1912490d67e6a99c3a91db433120b13768affef6b0cdeb33d085078fa27b90ef2663c69fcf9f3dad9a1fb67b9605f035b2cebf7808801e9ccd3eb83015aaefecf1fa97674923219c543accdc23d5f624cdbd673eba5f29cc66c647e1fe454e0c73efe8ff6605f78243e01aa42c14241f890388d6d35e3071ee89130f62317b8d624fc2b7c270769cf8e5c054cf3ed4163917f0af7372ab0eafdc4dd4faaf3cc30d406041404eae2ba942c800e4d9726e8e0d27e1488c5aaf47d977665c86d8574c17b69c8b31783ec479929e6b858ef57b072bcfaa3a747362235e142e9b73f19192d8878b832ff25b8cf29f0b5c130cb1d505ec1830a0901c0ac1f9b5542db33a9c39afc6ffa68d32a91dbb525cec9536647020cd22925baf63d173cd9b377fbcb509efcbf7830df459e080f5794186d628be938e9a53d3ea3182eb328d9956905dc6c22061c76118b208cdd7f063522d81ab4e404ef6d4a53b2099d2c94b8c05526b8367cfff6f08340bbe53cf2fbe6e7fae3b7062d27722085", - "9956a87c447eb15b82906742ef84980ca1dc6846b2234468ed7399af5392243b14226ab2a6ff6220776d1b5a591cacfde0bd583f48683d4f38186300f919681aa0a886e7eddc556e1bb434c18994df214a5b6fe4bfcb09ae9fc5dba4cb7e027ce01121dbad0621fe35311e1015c7d4d006ababd5c7377a0f70aecafaf3f709c0571ca2dd89b6cd83867bd299e8ce01e04ecafc1230ab0aeb2812a693fadcba7b479a00da357e75876d0cd2a3d85774e056d63436623ff400c9fd76446f5b7fd90902bf4d4268fb5775e326a887bd59136692bb5b0400790dd7908f9d5c7e422c76831ac3876e67a8b6d66ceb49c9c0835660bbd90a1e18ab8486dc464b6fd4044c580d3082842ab655169cf46abe25ad4de04d0bdefc74fee9c2009b43eea48f976a449ceb805993383b06ddfaf5a3df112a1c5e72ea121b9fbeafe8b7666500abeb52f2bad6035295b66994c0d239ced38f32af4df161b7bd66886703c050531173ae6ace942a311a0077b601c025bb59a78b43558c09ae55a6ce70d408b7e0ae439542971b33fdf14a7c5a36fed8d310e8cd08fe7c6b45d1bffd351bad2fd1cfc8d964f8ec39db82a7fd4095771f6d5e84516598364bd0532d3b8ccd660fa73bc1e5840087eeac18c7fd52611deac5aa50a6a033d2aecd79ec8bba8045615ff4d7b77e0d087110b888426d138107236ed4a6a6b6a5b51e54149e2272896d0180a46cde8955a8adeb969c35c5b58a0958ce955f2634723d8bf38c2d1c3efe0ce2494b00947d3958ec3b5b9f5445acad30296a34060bd688c7b91e818f49ddfa560541682ce0ff6d245b9df5adee989ea6b9eedcf58b3d47fdc64e8c046efaad51e169a81fc22419be8666897f18d7c913d806764714c9a735cce3698da8ecb3b16c1a88f6ef2b4a52686d4d1b5cfc5859422a1b39f7fe46691ccd28050a8edf040f438b407bfa4cc48641155e3c7531301d5192148ab2ccba064afeed1ae8723702ea9793317a1989a2601a958fda5bb23222a983842a31553930c4364b661e03376fff2471ae", - "4c19996b1ed254aba3f5d36a24a3a24a008cc864562610e15523087c2c05e63c57bc6c386d4f1b3cb53eb10ae26ab594a6693fa8ee5783ab4b4b040a0e4f27beda68405b72cbcbeee762114b23d1fe69aaf72bc81f70e76251df20b83fe6b82240fbe64be3b1a238bf3c5a8b7c8bac945fd25348b5618ff2409940f64bd86afb64695706c57340e72741af4e0d2d47407b041c57aac7ba9d35ce2316d6bff28ee5c22b007ec2c9b5914cb5baaa9e2ce6aafeb976c681dc08e1eb28514a7b7adfa0536ced06e3e23e9a14bad3f68b836442a952c39bfcaabdae0d3226dde590f3ba927b49a0c6f011b02abd14e5db8bf355432e3d3286c9aa5fcf2b6620cda13d56753a420555d0300de04c008d6cb9b62e4c7c44ea563445cccfc8266b06192c2981ce5b1157b6c16ca38e6b7036dd2e21e75646bbffc0be2f6c23257666a5679b8e35ac4382e31c05e4ef1170293617e6f77bd32b57f5ac617a7cbafa345c2137d8a7b70bf4a3b5c4010d73e7f064a9e5e51eaecf600bb837e0a648359aa4857b0875f14a62c648e7a7a13fac7e466bdd9ac89cf7f1f46081f5d107a6fffa5a0d8c70aa5aeaed3df35e9a5b33cabb98b22bf62d84cf4e57d7683457dbff3542a9299f9acd291225e4e8fc1255b305ca0e1404707053e50d55f69d8b709d9350db4f6f36ecf63037c6e00073df67b610c322e79ae4616314dc47d296b4570b659c21d659375fd1006af4d42838eb20f1682ffd19cf88b603790005b8c5ae4ab9c0415bcb0c8ce4a04d1f7d18fef5e16e9061aa56bc596bcdeae74ccdd1c95ab1607280602f75ddbb3a25cbe9af99197b0dab671a2e1069340cefcefef75e24e222c9e3d1563634eb3f3a8319bfd6f95b3a995d9dcad5a9aa2aea6bf46e6253080d8e4ec3b918d0012fe500edfba67e49d0520be57e7414629bb40e64312fb1d3e26bdef31cc8ec2426f71f91cfee0d3cd9390dceafe615106fd56703b85b377b812b8a6c24c9fc5d0c68464565d9b421a4cd296f00ddd7a062ea16c56232a4d2a69c2817bfa882", - "ba1edea16bd7223b3a413af6b392662b9b01eb18f67d41defe1cc4190160cf12c462414df90299b0ca5fbe7e2cf11f902a23de8340d9a190f32de0199ce150f15c6ed658638fe33701e3cee11574865efe768ecefd53ba20833e1300d4cc84bf0291852031fe5ce6b7dbd1bfe46d6887e39b6466b6ef76cd5743349c4109176bd0e60074bb7d8ba1cf47609b628045ed64743be510d90a21b7022f88a08dcabd7bc600c26b228b94ee175268f8206df72f7a708c014d162231e9009af0acacfb115674eb6fbb873e0c47b7b66820c7999143da38a871610614c8fe45a0c0d83020ed7c1e3eb5ee14e3e3bf70917a7d7a96e356e52c3bb33607448f61f592142de315fd29a172ce686b028c47cfb936780e1beebbbd2fca706534060e8d7f2de973005229183cd5ceaef3ceb944ca98562f22deec110ff6993ff9512f9b8e1aac17c08fa0295315229596a87eb0935e9b28ff1aff4d71889fed76fa7021e3494155b3b34f28cf5e717b46351bd9b11b0ddceac9ff3bd0c962ac003f5062acdb50058d50546d71fbb50e21221addd61a36f9ef98611f77d1c3c3ecc344fcdd9008d37ebe15944375ab767b1f937cb647dea26d7c6c8f9832b4f8632febba8abb107c39ba85ce09719eb7d7607ca6d0cc491419f6d3863e5d6f446a3c291da01c16e58e65b4428f8e0c024df391e6864e879bfc749d9175654c04413cbe4a65a35cea5596d6dc2d81800b2458fc75bfec6fedbbba857c24a19a0e747dc1d089b9eebb9b5098b2bcd2720f52d28055611ceb7b26d0c4b2a20c3b3aa9da50872bd95ef8154d6fd28669ffb48792e234a6f8eba3e53b57d994b8efd594045e0b6afb764013c28a23934a1502d0a90fe853e0a95738f1cdff79c7ee4e91d57824cd5cea56e8a45d95ee0cb1fa8911ccbd1e14883873817109f9ca4d21be60e3966541d1e1aaa7de0a57a3437f8a24e41a941d20f03055cd74f4b3048d2d9da7406da46ea82b65fd7b18e9004474583ecc9a2759b12fdd770f47222ef2c02d42ed0d18837a3e259f009d1e", - } - // This has been generated using the Functions Toolkit (https://github.com/smartcontractkit/functions-toolkit/blob/main/src/SecretsManager.ts) and decrypts to the JSON string `{"0x0":"qrvM"}` - DefaultThresholdSecretsHex = "0x7b225444483243747874223a2265794a48636d393163434936496c41794e5459694c434a44496a6f69533035305a5559325448593056553168543341766148637955584a4b65545a68626b3177527939794f464e78576a59356158646d636a6c4f535430694c434a4d59574a6c62434936496b464251554642515546425155464251554642515546425155464251554642515546425155464251554642515546425155464251554642515545394969776956534936496b4a45536c6c7a51334e7a623055334d6e6444574846474e557056634770585a573157596e565265544d796431526d4d32786c636c705a647a4671536e6c47627a5256615735744e6d773355456855546e6b7962324e746155686f626c51354d564a6a4e6e5230656c70766147644255326372545430694c434a5658324a6863694936496b4a4961544e69627a5a45536d396a4d324d344d6c46614d5852724c325645536b4a484d336c5a556d783555306834576d684954697472623264575a306f33546e4e456232314b5931646853544979616d63305657644f556c526e57465272655570325458706952306c4a617a466e534851314f4430694c434a46496a6f694d7a524956466c354d544e474b307836596e5a584e7a6c314d6d356c655574514e6b397a656e467859335253513239705a315534534652704e4430694c434a47496a6f69557a5132596d6c6952545a584b314176546d744252445677575459796148426862316c6c6330684853556869556c56614e303155556c6f345554306966513d3d222c2253796d43747874223a2253764237652f4a556a552b433358757873384e5378316967454e517759755051623730306a4a6144222c224e6f6e6365223a224d31714b557a6b306b77374767593538227d" -) diff --git a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go deleted file mode 100644 index 9013620e1e6..00000000000 --- a/core/services/ocr2/plugins/functions/integration_tests/v0/internal/testutils.go +++ /dev/null @@ -1,565 +0,0 @@ -package testutils - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "io" - "math/big" - "math/rand" - "net" - "net/http" - "net/http/httptest" - "net/url" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/onsi/gomega" - "github.com/smartcontractkit/libocr/commontypes" - confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_client_example" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_oracle" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/ocr2dr_registry" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/functions" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func ptr[T any](v T) *T { return &v } - -func SetOracleConfig(t *testing.T, owner *bind.TransactOpts, oracleContract *ocr2dr_oracle.OCR2DROracle, oracles []confighelper2.OracleIdentityExtra, batchSize int, functionsPluginConfig *functionsConfig.ReportingPluginConfig) { - S := make([]int, len(oracles)) - for i := 0; i < len(S); i++ { - S[i] = 1 - } - - reportingPluginConfigBytes, err := functionsConfig.EncodeReportingPluginConfig(&functionsConfig.ReportingPluginConfigWrapper{ - Config: functionsPluginConfig, - }) - require.NoError(t, err) - - signersKeys, transmittersAccounts, f, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper2.ContractSetConfigArgsForTests( - 2*time.Second, // deltaProgress - 1*time.Second, // deltaResend - 1*time.Second, // deltaRound - 500*time.Millisecond, // deltaGrace - 2*time.Second, // deltaStage - 5, // RMax (maxRounds) - S, // S (schedule of randomized transmission order) - oracles, - reportingPluginConfigBytes, - 200*time.Millisecond, // maxDurationQuery - 200*time.Millisecond, // maxDurationObservation - 200*time.Millisecond, // maxDurationReport - 200*time.Millisecond, // maxDurationAccept - 200*time.Millisecond, // maxDurationTransmit - 1, // f (max faulty oracles) - nil, // empty onChain config - ) - - var signers []common.Address - var transmitters []common.Address - for i := range signersKeys { - signers = append(signers, common.BytesToAddress(signersKeys[i])) - transmitters = append(transmitters, common.HexToAddress(string(transmittersAccounts[i]))) - } - - require.NoError(t, err) - _, err = oracleContract.SetConfig( - owner, - signers, - transmitters, - f, - onchainConfig, - offchainConfigVersion, - offchainConfig, - ) - require.NoError(t, err) - _, err = oracleContract.DeactivateAuthorizedReceiver(owner) - require.NoError(t, err) -} - -func SetRegistryConfig(t *testing.T, owner *bind.TransactOpts, registryContract *ocr2dr_registry.OCR2DRRegistry, oracleContractAddress common.Address) { - var maxGasLimit = uint32(450_000) - var stalenessSeconds = uint32(86_400) - var gasAfterPaymentCalculation = big.NewInt(21_000 + 5_000 + 2_100 + 20_000 + 2*2_100 - 15_000 + 7_315) - var weiPerUnitLink = big.NewInt(5000000000000000) - var gasOverhead = uint32(500_000) - var requestTimeoutSeconds = uint32(300) - - _, err := registryContract.SetConfig( - owner, - maxGasLimit, - stalenessSeconds, - gasAfterPaymentCalculation, - weiPerUnitLink, - gasOverhead, - requestTimeoutSeconds, - ) - require.NoError(t, err) - - var senders = []common.Address{oracleContractAddress} - _, err = registryContract.SetAuthorizedSenders( - owner, - senders, - ) - require.NoError(t, err) -} - -func CreateAndFundSubscriptions(t *testing.T, owner *bind.TransactOpts, linkToken *link_token_interface.LinkToken, registryContractAddress common.Address, registryContract *ocr2dr_registry.OCR2DRRegistry, clientContracts []deployedClientContract) (subscriptionId uint64) { - _, err := registryContract.CreateSubscription(owner) - require.NoError(t, err) - - subscriptionID := uint64(1) - - numContracts := len(clientContracts) - for i := 0; i < numContracts; i++ { - _, err = registryContract.AddConsumer(owner, subscriptionID, clientContracts[i].Address) - require.NoError(t, err) - } - - data, err := utils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) - require.NoError(t, err) - - amount := big.NewInt(0).Mul(big.NewInt(int64(numContracts)), big.NewInt(2e18)) // 2 LINK per client - _, err = linkToken.TransferAndCall(owner, registryContractAddress, amount, data) - require.NoError(t, err) - - time.Sleep(1000 * time.Millisecond) - - return subscriptionID -} - -const finalityDepth int = 4 - -func CommitWithFinality(b *backends.SimulatedBackend) { - for i := 0; i < finalityDepth; i++ { - b.Commit() - } -} - -type deployedClientContract struct { - Address common.Address - Contract *ocr2dr_client_example.OCR2DRClientExample -} - -func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, *backends.SimulatedBackend, *time.Ticker, common.Address, *ocr2dr_oracle.OCR2DROracle, []deployedClientContract, common.Address, *ocr2dr_registry.OCR2DRRegistry, *link_token_interface.LinkToken) { - owner := testutils.MustNewSimTransactor(t) - owner.GasPrice = big.NewInt(int64(DefaultGasPrice)) - sb := new(big.Int) - sb, _ = sb.SetString("100000000000000000000", 10) // 1 eth - genesisData := core.GenesisAlloc{owner.From: {Balance: sb}} - gasLimit := ethconfig.Defaults.Miner.GasCeil * 2 - b := backends.NewSimulatedBackend(genesisData, gasLimit) - b.Commit() - - // Deploy contracts - linkAddr, _, linkToken, err := link_token_interface.DeployLinkToken(owner, b) - require.NoError(t, err) - - linkEthFeedAddr, _, _, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(owner, b, 0, big.NewInt(5021530000000000)) - require.NoError(t, err) - - ocrContractAddress, _, ocrContract, err := ocr2dr_oracle.DeployOCR2DROracle(owner, b) - require.NoError(t, err) - - registryAddress, _, registryContract, err := ocr2dr_registry.DeployOCR2DRRegistry(owner, b, linkAddr, linkEthFeedAddr, ocrContractAddress) - require.NoError(t, err) - - _, err = ocrContract.SetRegistry(owner, registryAddress) - require.NoError(t, err) - - clientContracts := []deployedClientContract{} - for i := 0; i < nClients; i++ { - clientContractAddress, _, clientContract, err := ocr2dr_client_example.DeployOCR2DRClientExample(owner, b, ocrContractAddress) - require.NoError(t, err) - clientContracts = append(clientContracts, deployedClientContract{ - Address: clientContractAddress, - Contract: clientContract, - }) - if i%10 == 0 { - // Max 10 requests per block - b.Commit() - } - } - CommitWithFinality(b) - ticker := time.NewTicker(1 * time.Second) - go func() { - for range ticker.C { - b.Commit() - } - }() - return owner, b, ticker, ocrContractAddress, ocrContract, clientContracts, registryAddress, registryContract, linkToken -} - -type Node struct { - App *cltest.TestApplication - PeerID string - Transmitter common.Address - Keybundle ocr2key.KeyBundle - OracleIdentity confighelper2.OracleIdentityExtra -} - -func StartNewNode( - t *testing.T, - owner *bind.TransactOpts, - port uint16, - dbName string, - b *backends.SimulatedBackend, - maxGas uint32, - p2pV2Bootstrappers []commontypes.BootstrapperLocator, - ocr2Keystore []byte, - thresholdKeyShare string, -) *Node { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) - config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { - c.Insecure.OCRDevelopmentMode = ptr(true) - - c.Feature.LogPoller = ptr(true) - - c.OCR.Enabled = ptr(false) - c.OCR2.Enabled = ptr(true) - - c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} - if len(p2pV2Bootstrappers) > 0 { - c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers - } - - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) - c.EVM[0].Transactions.ForwardersEnabled = ptr(false) - c.EVM[0].GasEstimator.LimitDefault = ptr(maxGas) - c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") - c.EVM[0].GasEstimator.PriceDefault = assets.NewWei(big.NewInt(int64(DefaultGasPrice))) - - if len(thresholdKeyShare) > 0 { - s.Threshold.ThresholdKeyShare = models.NewSecret(thresholdKeyShare) - } - }) - - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) - require.NoError(t, err) - require.Len(t, sendingKeys, 1) - transmitter := sendingKeys[0].Address - - // fund the transmitter address - n, err := b.NonceAt(testutils.Context(t), owner.From, nil) - require.NoError(t, err) - - tx := types.NewTransaction( - n, transmitter, - assets.Ether(1).ToInt(), - 21000, - assets.GWei(1).ToInt(), - nil) - signedTx, err := owner.Signer(owner.From, tx) - require.NoError(t, err) - err = b.SendTransaction(testutils.Context(t), signedTx) - require.NoError(t, err) - b.Commit() - - var kb ocr2key.KeyBundle - if ocr2Keystore != nil { - kb, err = app.GetKeyStore().OCR2().Import(ocr2Keystore, "testPassword") - } else { - kb, err = app.GetKeyStore().OCR2().Create("evm") - } - require.NoError(t, err) - - err = app.Start(testutils.Context(t)) - require.NoError(t, err) - - return &Node{ - App: app, - PeerID: p2pKey.PeerID().Raw(), - Transmitter: transmitter, - Keybundle: kb, - OracleIdentity: confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: kb.PublicKey(), - TransmitAccount: ocrtypes2.Account(transmitter.String()), - OffchainPublicKey: kb.OffchainPublicKey(), - PeerID: p2pKey.PeerID().Raw(), - }, - ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(), - }, - } -} - -func AddBootstrapJob(t *testing.T, app *cltest.TestApplication, contractAddress common.Address) job.Job { - job, err := ocrbootstrap.ValidatedBootstrapSpecToml(fmt.Sprintf(` - type = "bootstrap" - name = "functions-bootstrap" - schemaVersion = 1 - relay = "evm" - contractConfigConfirmations = 1 - contractConfigTrackerPollInterval = "1s" - contractID = "%s" - - [relayConfig] - chainID = 1337 - fromBlock = 1 - `, contractAddress)) - require.NoError(t, err) - err = app.AddJobV2(testutils.Context(t), &job) - require.NoError(t, err) - return job -} - -func AddOCR2Job(t *testing.T, app *cltest.TestApplication, contractAddress common.Address, keyBundleID string, transmitter common.Address, bridgeURL string) job.Job { - u, err := url.Parse(bridgeURL) - require.NoError(t, err) - require.NoError(t, app.BridgeORM().CreateBridgeType(&bridges.BridgeType{ - Name: "ea_bridge", - URL: models.WebURL(*u), - })) - job, err := validate.ValidatedOracleSpecToml(app.Config.OCR2(), app.Config.Insecure(), fmt.Sprintf(` - type = "offchainreporting2" - name = "functions-node" - schemaVersion = 1 - relay = "evm" - contractID = "%s" - ocrKeyBundleID = "%s" - transmitterID = "%s" - contractConfigConfirmations = 1 - contractConfigTrackerPollInterval = "1s" - pluginType = "functions" - observationSource = """ - run_computation [type="bridge" name="ea_bridge" requestData="{\\"note\\": \\"observationSource is unused but the bridge is required\\"}"] - run_computation - """ - - [relayConfig] - chainID = 1337 - fromBlock = 1 - - [pluginConfig] - minIncomingConfirmations = 3 - requestTimeoutSec = 300 - requestTimeoutCheckFrequencySec = 10 - requestTimeoutBatchLookupSize = 20 - listenerEventHandlerTimeoutSec = 120 - maxRequestSizeBytes = 30720 - - [pluginConfig.decryptionQueueConfig] - completedCacheTimeoutSec = 300 - maxCiphertextBytes = 10_000 - maxCiphertextIdLength = 100 - maxQueueLength = 100 - decryptRequestTimeoutSec = 100 - - [pluginConfig.s4Constraints] - maxPayloadSizeBytes = 10_1000 - maxSlotsPerUser = 10 - `, contractAddress, keyBundleID, transmitter)) - require.NoError(t, err) - err = app.AddJobV2(testutils.Context(t), &job) - require.NoError(t, err) - return job -} - -func StartNewMockEA(t *testing.T) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - b, err := io.ReadAll(req.Body) - require.NoError(t, err) - var jsonMap map[string]any - require.NoError(t, json.Unmarshal(b, &jsonMap)) - var responsePayload []byte - if jsonMap["endpoint"].(string) == "lambda" { - responsePayload = mockEALambdaExecutionResponse(t, jsonMap) - } else if jsonMap["endpoint"].(string) == "fetcher" { - responsePayload = mockEASecretsFetchResponse(t, jsonMap) - } else { - require.Fail(t, "unknown external adapter endpoint '%s'", jsonMap["endpoint"].(string)) - } - res.WriteHeader(http.StatusOK) - _, err = res.Write(responsePayload) - require.NoError(t, err) - })) -} - -func mockEALambdaExecutionResponse(t *testing.T, request map[string]any) []byte { - data := request["data"].(map[string]any) - require.Equal(t, functions.LanguageJavaScript, int(data["language"].(float64))) - require.Equal(t, functions.LocationInline, int(data["codeLocation"].(float64))) - require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) - if data["secrets"] != DefaultSecretsBase64 && request["nodeProvidedSecrets"] != fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64) { - assert.Fail(t, "expected secrets or nodeProvidedSecrets to be '%s'", DefaultSecretsBase64) - } - args := data["args"].([]interface{}) - require.Equal(t, 2, len(args)) - require.Equal(t, DefaultArg1, args[0].(string)) - require.Equal(t, DefaultArg2, args[1].(string)) - source := data["source"].(string) - // prepend "0xab" to source and return as result - return []byte(fmt.Sprintf(`{"result": "success", "statusCode": 200, "data": {"result": "0xab%s", "error": ""}}`, source)) -} - -func mockEASecretsFetchResponse(t *testing.T, request map[string]any) []byte { - data := request["data"].(map[string]any) - require.Equal(t, "fetchThresholdEncryptedSecrets", data["requestType"]) - require.Equal(t, DefaultSecretsUrlsBase64, data["encryptedSecretsUrls"]) - return []byte(fmt.Sprintf(`{"result": "success", "statusCode": 200, "data": {"result": "%s", "error": ""}}`, DefaultThresholdSecretsHex)) -} - -// Mock EA prepends 0xab to source and user contract crops the answer to first 32 bytes -func GetExpectedResponse(source []byte) [32]byte { - var resp [32]byte - resp[0] = 0xab - for j := 0; j < 31; j++ { - if j >= len(source) { - break - } - resp[j+1] = source[j] - } - return resp -} - -func CreateFunctionsNodes( - t *testing.T, - owner *bind.TransactOpts, - b *backends.SimulatedBackend, - oracleContractAddress common.Address, - nOracleNodes int, - maxGas int, - ocr2Keystores [][]byte, - thresholdKeyShares []string, -) (bootstrapNode *Node, oracleNodes []*cltest.TestApplication, oracleIdentites []confighelper2.OracleIdentityExtra) { - t.Helper() - - if len(thresholdKeyShares) != 0 && len(thresholdKeyShares) != nOracleNodes { - require.Fail(t, "thresholdKeyShares must be empty or have length equal to nOracleNodes") - } - if len(ocr2Keystores) != 0 && len(ocr2Keystores) != nOracleNodes { - require.Fail(t, "ocr2Keystores must be empty or have length equal to nOracleNodes") - } - if len(ocr2Keystores) != len(thresholdKeyShares) { - require.Fail(t, "ocr2Keystores and thresholdKeyShares must have the same length") - } - - bootstrapPort := getFreePort(t) - bootstrapNode = StartNewNode(t, owner, bootstrapPort, "bootstrap", b, uint32(maxGas), nil, nil, "") - AddBootstrapJob(t, bootstrapNode.App, oracleContractAddress) - - // oracle nodes with jobs, bridges and mock EAs - for i := 0; i < nOracleNodes; i++ { - var thresholdKeyShare string - if len(thresholdKeyShares) == 0 { - thresholdKeyShare = "" - } else { - thresholdKeyShare = thresholdKeyShares[i] - } - var ocr2Keystore []byte - if len(ocr2Keystores) == 0 { - ocr2Keystore = nil - } else { - ocr2Keystore = ocr2Keystores[i] - } - nodePort := getFreePort(t) - oracleNode := StartNewNode(t, owner, nodePort, fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ - {PeerID: bootstrapNode.PeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapPort)}}, - }, ocr2Keystore, thresholdKeyShare) - oracleNodes = append(oracleNodes, oracleNode.App) - oracleIdentites = append(oracleIdentites, oracleNode.OracleIdentity) - - ea := StartNewMockEA(t) - t.Cleanup(ea.Close) - - _ = AddOCR2Job(t, oracleNodes[i], oracleContractAddress, oracleNode.Keybundle.ID(), oracleNode.Transmitter, ea.URL) - } - - return bootstrapNode, oracleNodes, oracleIdentites -} - -// NOTE: This approach is technically incorrect because the returned port -// can still be taken by the time the caller attempts to bind to it. -// Unfortunately, we can't specify zero port in P2P.V2.ListenAddresses at the moment. -func getFreePort(t *testing.T) uint16 { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - require.NoError(t, err) - listener, err := net.ListenTCP("tcp", addr) - require.NoError(t, err) - require.NoError(t, listener.Close()) - return uint16(listener.Addr().(*net.TCPAddr).Port) -} - -func ClientTestRequests( - t *testing.T, - owner *bind.TransactOpts, - b *backends.SimulatedBackend, - linkToken *link_token_interface.LinkToken, - registryAddress common.Address, - registryContract *ocr2dr_registry.OCR2DRRegistry, - clientContracts []deployedClientContract, - requestLenBytes int, - expectedSecrets []byte, - timeout time.Duration, -) { - t.Helper() - subscriptionId := CreateAndFundSubscriptions(t, owner, linkToken, registryAddress, registryContract, clientContracts) - // send requests - requestSources := make([][]byte, len(clientContracts)) - rnd := rand.New(rand.NewSource(666)) - for i, client := range clientContracts { - requestSources[i] = make([]byte, requestLenBytes) - for j := 0; j < requestLenBytes; j++ { - requestSources[i][j] = byte(rnd.Uint32() % 256) - } - _, err := client.Contract.SendRequest( - owner, - hex.EncodeToString(requestSources[i]), - expectedSecrets, - []string{DefaultArg1, DefaultArg2}, - subscriptionId) - require.NoError(t, err) - } - CommitWithFinality(b) - - // validate that all client contracts got correct responses to their requests - var wg sync.WaitGroup - for i := 0; i < len(clientContracts); i++ { - ic := i - wg.Add(1) - go func() { - defer wg.Done() - gomega.NewGomegaWithT(t).Eventually(func() [32]byte { - answer, err := clientContracts[ic].Contract.LastResponse(nil) - require.NoError(t, err) - return answer - }, timeout, 1*time.Second).Should(gomega.Equal(GetExpectedResponse(requestSources[ic]))) - }() - } - wg.Wait() -} diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go b/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go index 944bafadf75..e92cbe8bca4 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/functions_integration_test.go @@ -44,7 +44,7 @@ func TestIntegration_Functions_MultipleV1Requests_Success(t *testing.T) { subscriptionId := utils.CreateAndFundSubscriptions(t, b, owner, linkToken, routerAddress, routerContract, clientContracts, allowListContract) b.Commit() - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, nil, subscriptionId, 1*time.Minute) } func TestIntegration_Functions_MultipleV1Requests_ThresholdDecryptionSuccess(t *testing.T) { @@ -91,7 +91,7 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { utils.SetupRouterRoutes(t, b, owner, routerContract, active.Address, proposed.Address, allowListContractAddress) - _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, routerAddress, nOracleNodes, maxGas, nil, nil) + _, _, oracleIdentities := utils.CreateFunctionsNodes(t, owner, b, routerAddress, nOracleNodes, maxGas, utils.ExportedOcr2Keystores, utils.MockThresholdKeyShares) pluginConfig := functionsConfig.ReportingPluginConfig{ MaxQueryLengthBytes: 10_000, @@ -101,6 +101,16 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { MaxReportTotalCallbackGas: uint32(maxTotalReportGas), DefaultAggregationMethod: functionsConfig.AggregationMethod_AGGREGATION_MODE, UniqueReports: true, + ThresholdPluginConfig: &functionsConfig.ThresholdReportingPluginConfig{ + // approximately 750 bytes per test ciphertext + overhead + MaxQueryLengthBytes: 70_000, + MaxObservationLengthBytes: 70_000, + MaxReportLengthBytes: 70_000, + RequestCountLimit: 50, + RequestTotalBytesLimit: 50_000, + RequireLocalRequestCheck: true, + K: 2, + }, } // set config for both coordinators @@ -108,11 +118,11 @@ func TestIntegration_Functions_MultipleV1Requests_WithUpgrade(t *testing.T) { utils.SetOracleConfig(t, b, owner, proposed.Contract, oracleIdentities, batchSize, &pluginConfig) subscriptionId := utils.CreateAndFundSubscriptions(t, b, owner, linkToken, routerAddress, routerContract, clientContracts, allowListContract) - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsUrlsBytes, subscriptionId, 1*time.Minute) // upgrade and send requests again _, err := routerContract.UpdateContracts(owner) require.NoError(t, err) b.Commit() - utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsBytes, subscriptionId, 1*time.Minute) + utils.ClientTestRequests(t, owner, b, linkToken, routerAddress, routerContract, allowListContract, clientContracts, requestLenBytes, utils.DefaultSecretsUrlsBytes, subscriptionId, 1*time.Minute) } diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index c376213ed13..5c824323eb6 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -7,7 +7,6 @@ import ( "io" "math/big" "math/rand" - "net" "net/http" "net/http/httptest" "net/url" @@ -22,12 +21,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/commontypes" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -43,8 +43,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/functions" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" @@ -224,6 +224,7 @@ func StartNewChainWithContracts(t *testing.T, nClients int) (*bind.TransactOpts, MaxSupportedRequestDataVersion: uint16(1), FulfillmentGasPriceOverEstimationBP: uint32(1_000), FallbackNativePerUnitLink: big.NewInt(5_000_000_000_000_000), + MinimumEstimateGasPriceWei: big.NewInt(1_000_000_000), } require.NoError(t, err) coordinatorAddress, _, coordinatorContract, err := functions_coordinator.DeployFunctionsCoordinator(owner, b, routerAddress, coordinatorConfig, linkEthFeedAddr) @@ -300,7 +301,7 @@ type Node struct { func StartNewNode( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, b *backends.SimulatedBackend, maxGas uint32, @@ -308,8 +309,7 @@ func StartNewNode( ocr2Keystore []byte, thresholdKeyShare string, ) *Node { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) + p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) @@ -494,9 +494,9 @@ func mockEALambdaExecutionResponse(t *testing.T, request map[string]any) []byte data := request["data"].(map[string]any) require.Equal(t, functions.LanguageJavaScript, int(data["language"].(float64))) require.Equal(t, functions.LocationInline, int(data["codeLocation"].(float64))) - require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) - if data["secrets"] != DefaultSecretsBase64 && request["nodeProvidedSecrets"] != fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64) { - assert.Fail(t, "expected secrets or nodeProvidedSecrets to be '%s'", DefaultSecretsBase64) + if len(request["nodeProvidedSecrets"].(string)) > 0 { + require.Equal(t, functions.LocationRemote, int(data["secretsLocation"].(float64))) + require.Equal(t, fmt.Sprintf(`{"0x0":"%s"}`, DefaultSecretsBase64), request["nodeProvidedSecrets"].(string)) } args := data["args"].([]interface{}) require.Equal(t, 2, len(args)) @@ -549,11 +549,12 @@ func CreateFunctionsNodes( require.Fail(t, "ocr2Keystores and thresholdKeyShares must have the same length") } - bootstrapPort := getFreePort(t) + bootstrapPort := freeport.GetOne(t) bootstrapNode = StartNewNode(t, owner, bootstrapPort, "bootstrap", b, uint32(maxGas), nil, nil, "") AddBootstrapJob(t, bootstrapNode.App, routerAddress) // oracle nodes with jobs, bridges and mock EAs + ports := freeport.GetN(t, nOracleNodes) for i := 0; i < nOracleNodes; i++ { var thresholdKeyShare string if len(thresholdKeyShares) == 0 { @@ -567,8 +568,7 @@ func CreateFunctionsNodes( } else { ocr2Keystore = ocr2Keystores[i] } - nodePort := getFreePort(t) - oracleNode := StartNewNode(t, owner, nodePort, fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ + oracleNode := StartNewNode(t, owner, ports[i], fmt.Sprintf("oracle%d", i), b, uint32(maxGas), []commontypes.BootstrapperLocator{ {PeerID: bootstrapNode.PeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapPort)}}, }, ocr2Keystore, thresholdKeyShare) oracleNodes = append(oracleNodes, oracleNode.App) @@ -583,18 +583,6 @@ func CreateFunctionsNodes( return bootstrapNode, oracleNodes, oracleIdentites } -// NOTE: This approach is technically incorrect because the returned port -// can still be taken by the time the caller attempts to bind to it. -// Unfortunately, we can't specify zero port in P2P.V2.ListenAddresses at the moment. -func getFreePort(t *testing.T) uint16 { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - require.NoError(t, err) - listener, err := net.ListenTCP("tcp", addr) - require.NoError(t, err) - require.NoError(t, listener.Close()) - return uint16(listener.Addr().(*net.TCPAddr).Port) -} - func ClientTestRequests( t *testing.T, owner *bind.TransactOpts, diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 6cc7da97d00..10f780371b2 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -3,12 +3,12 @@ package functions import ( "encoding/json" "math/big" + "slices" "time" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/smartcontractkit/sqlx" - "golang.org/x/exp/slices" "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" @@ -110,9 +110,7 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs pluginORM, pluginConfig, s4Storage, - conf.Chain.LogBroadcaster(), listenerLogger, - conf.MailMon, conf.URLsMonEndpoint, decryptor, conf.LogPollerWrapper, diff --git a/core/services/ocr2/plugins/functions/reporting.go b/core/services/ocr2/plugins/functions/reporting.go index f2e2f86aba2..dfa8f575d1b 100644 --- a/core/services/ocr2/plugins/functions/reporting.go +++ b/core/services/ocr2/plugins/functions/reporting.go @@ -157,17 +157,15 @@ func (r *functionsReporting) Query(ctx context.Context, ts types.ReportTimestamp var reportCoordinator *common.Address for _, result := range results { result := result - if r.contractVersion == 1 { - reportCoordinator, err = ShouldIncludeCoordinator(result.CoordinatorContractAddress, reportCoordinator) - if err != nil { - r.logger.Debug("FunctionsReporting Query: skipping request with mismatched coordinator contract address", commontypes.LogFields{ - "requestID": formatRequestId(result.RequestID[:]), - "requestCoordinator": result.CoordinatorContractAddress, - "reportCoordinator": reportCoordinator, - "error": err, - }) - continue - } + reportCoordinator, err = ShouldIncludeCoordinator(result.CoordinatorContractAddress, reportCoordinator) + if err != nil { + r.logger.Debug("FunctionsReporting Query: skipping request with mismatched coordinator contract address", commontypes.LogFields{ + "requestID": formatRequestId(result.RequestID[:]), + "requestCoordinator": result.CoordinatorContractAddress, + "reportCoordinator": reportCoordinator, + "error": err, + }) + continue } queryProto.RequestIDs = append(queryProto.RequestIDs, result.RequestID[:]) idStrs = append(idStrs, formatRequestId(result.RequestID[:])) @@ -236,16 +234,14 @@ func (r *functionsReporting) Observation(ctx context.Context, ts types.ReportTim Error: localResult.Error, OnchainMetadata: localResult.OnchainMetadata, } - if r.contractVersion == 1 { - if localResult.CallbackGasLimit == nil || localResult.CoordinatorContractAddress == nil { - r.logger.Error("FunctionsReporting Observation missing required v1 fields", commontypes.LogFields{ - "requestID": formatRequestId(id[:]), - }) - continue - } - resultProto.CallbackGasLimit = *localResult.CallbackGasLimit - resultProto.CoordinatorContract = localResult.CoordinatorContractAddress[:] + if localResult.CallbackGasLimit == nil || localResult.CoordinatorContractAddress == nil { + r.logger.Error("FunctionsReporting Observation missing required v1 fields", commontypes.LogFields{ + "requestID": formatRequestId(id[:]), + }) + continue } + resultProto.CallbackGasLimit = *localResult.CallbackGasLimit + resultProto.CoordinatorContract = localResult.CoordinatorContractAddress[:] observationProto.ProcessedRequests = append(observationProto.ProcessedRequests, &resultProto) idStrs = append(idStrs, formatRequestId(localResult.RequestID[:])) } @@ -367,19 +363,17 @@ func (r *functionsReporting) Report(ctx context.Context, ts types.ReportTimestam "requestID": reqId, "nObservations": len(observations), }) - if r.contractVersion == 1 { - var requestCoordinator common.Address - requestCoordinator.SetBytes(aggregated.CoordinatorContract) - reportCoordinator, err = ShouldIncludeCoordinator(&requestCoordinator, reportCoordinator) - if err != nil { - r.logger.Error("FunctionsReporting Report: skipping request with mismatched coordinator contract address", commontypes.LogFields{ - "requestID": reqId, - "requestCoordinator": requestCoordinator, - "reportCoordinator": reportCoordinator, - "error": err, - }) - continue - } + var requestCoordinator common.Address + requestCoordinator.SetBytes(aggregated.CoordinatorContract) + reportCoordinator, err = ShouldIncludeCoordinator(&requestCoordinator, reportCoordinator) + if err != nil { + r.logger.Error("FunctionsReporting Report: skipping request with mismatched coordinator contract address", commontypes.LogFields{ + "requestID": reqId, + "requestCoordinator": requestCoordinator, + "reportCoordinator": reportCoordinator, + "error": err, + }) + continue } allAggregated = append(allAggregated, aggregated) allIdStrs = append(allIdStrs, reqId) diff --git a/core/services/ocr2/plugins/functions/reporting_test.go b/core/services/ocr2/plugins/functions/reporting_test.go index 6d5126c9390..24b430abd93 100644 --- a/core/services/ocr2/plugins/functions/reporting_test.go +++ b/core/services/ocr2/plugins/functions/reporting_test.go @@ -22,14 +22,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" ) -func preparePlugin(t *testing.T, batchSize uint32, contractVersion uint32, maxTotalGasLimit uint32) (types.ReportingPlugin, *functions_mocks.ORM, encoding.ReportCodec) { +func preparePlugin(t *testing.T, batchSize uint32, maxTotalGasLimit uint32) (types.ReportingPlugin, *functions_mocks.ORM, encoding.ReportCodec) { lggr := logger.TestLogger(t) ocrLogger := relaylogger.NewOCRWrapper(lggr, true, func(msg string) {}) orm := functions_mocks.NewORM(t) factory := functions.FunctionsReportingPluginFactory{ Logger: ocrLogger, PluginORM: orm, - ContractVersion: contractVersion, + ContractVersion: 1, } pluginConfig := config.ReportingPluginConfigWrapper{ @@ -46,7 +46,7 @@ func preparePlugin(t *testing.T, batchSize uint32, contractVersion uint32, maxTo OffchainConfig: pluginConfigBytes, }) require.NoError(t, err) - codec, err := encoding.NewReportCodec(contractVersion) + codec, err := encoding.NewReportCodec(1) require.NoError(t, err) return plugin, orm, codec } @@ -56,23 +56,33 @@ func newRequestID() functions_srv.RequestID { } func newRequest() functions_srv.Request { - return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.IN_PROGRESS} + var gasLimit uint32 = 100000 + return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.IN_PROGRESS, CoordinatorContractAddress: &common.Address{1}, CallbackGasLimit: &gasLimit} } func newRequestWithResult(result []byte) functions_srv.Request { - return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.RESULT_READY, Result: result} + req := newRequest() + req.State = functions_srv.RESULT_READY + req.Result = result + return req } func newRequestFinalized() functions_srv.Request { - return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.FINALIZED} + req := newRequest() + req.State = functions_srv.FINALIZED + return req } func newRequestTimedOut() functions_srv.Request { - return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.TIMED_OUT} + req := newRequest() + req.State = functions_srv.TIMED_OUT + return req } func newRequestConfirmed() functions_srv.Request { - return functions_srv.Request{RequestID: newRequestID(), State: functions_srv.CONFIRMED} + req := newRequest() + req.State = functions_srv.CONFIRMED + return req } func newMarshalledQuery(t *testing.T, reqIDs ...functions_srv.RequestID) []byte { @@ -89,9 +99,10 @@ func newMarshalledQuery(t *testing.T, reqIDs ...functions_srv.RequestID) []byte func newProcessedRequest(requestId functions_srv.RequestID, compResult []byte, compError []byte) *encoding.ProcessedRequest { return &encoding.ProcessedRequest{ - RequestID: requestId[:], - Result: compResult, - Error: compError, + RequestID: requestId[:], + Result: compResult, + Error: compError, + CoordinatorContract: []byte{1}, } } @@ -119,7 +130,7 @@ func newObservation(t *testing.T, observerId uint8, requests ...*encoding.Proces func TestFunctionsReporting_Query(t *testing.T) { t.Parallel() const batchSize = 10 - plugin, orm, _ := preparePlugin(t, batchSize, 0, 0) + plugin, orm, _ := preparePlugin(t, batchSize, 0) reqs := []functions_srv.Request{newRequest(), newRequest()} orm.On("FindOldestEntriesByState", functions_srv.RESULT_READY, uint32(batchSize), mock.Anything).Return(reqs, nil) @@ -137,7 +148,7 @@ func TestFunctionsReporting_Query(t *testing.T) { func TestFunctionsReporting_Query_HandleCoordinatorMismatch(t *testing.T) { t.Parallel() const batchSize = 10 - plugin, orm, _ := preparePlugin(t, batchSize, 1, 1000000) + plugin, orm, _ := preparePlugin(t, batchSize, 1000000) reqs := []functions_srv.Request{newRequest(), newRequest()} reqs[0].CoordinatorContractAddress = &common.Address{1} reqs[1].CoordinatorContractAddress = &common.Address{2} @@ -156,7 +167,7 @@ func TestFunctionsReporting_Query_HandleCoordinatorMismatch(t *testing.T) { func TestFunctionsReporting_Observation(t *testing.T) { t.Parallel() - plugin, orm, _ := preparePlugin(t, 10, 0, 0) + plugin, orm, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("abc")) req2 := newRequest() @@ -191,7 +202,7 @@ func TestFunctionsReporting_Observation(t *testing.T) { func TestFunctionsReporting_Observation_IncorrectQuery(t *testing.T) { t.Parallel() - plugin, orm, _ := preparePlugin(t, 10, 0, 0) + plugin, orm, _ := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("abc")) invalidId := []byte("invalid") @@ -218,7 +229,7 @@ func TestFunctionsReporting_Observation_IncorrectQuery(t *testing.T) { func TestFunctionsReporting_Report(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 0, 0) + plugin, _, codec := preparePlugin(t, 10, 1000000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") procReq1 := newProcessedRequest(reqId1, compResult, []byte{}) @@ -255,7 +266,7 @@ func TestFunctionsReporting_Report(t *testing.T) { func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 1, 300000) + plugin, _, codec := preparePlugin(t, 10, 300000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") gasLimit1, gasLimit2 := uint32(100_000), uint32(200_000) @@ -296,7 +307,7 @@ func TestFunctionsReporting_Report_WithGasLimitAndMetadata(t *testing.T) { func TestFunctionsReporting_Report_HandleCoordinatorMismatch(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 1, 300000) + plugin, _, codec := preparePlugin(t, 10, 300000) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult, meta := []byte("aaa"), []byte("meta") coordinatorContractA, coordinatorContractB := common.Address{1}, common.Address{2} @@ -326,7 +337,7 @@ func TestFunctionsReporting_Report_HandleCoordinatorMismatch(t *testing.T) { func TestFunctionsReporting_Report_CallbackGasLimitExceeded(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 1, 200000) + plugin, _, codec := preparePlugin(t, 10, 200000) reqId1, reqId2 := newRequestID(), newRequestID() compResult := []byte("aaa") gasLimit1, gasLimit2 := uint32(100_000), uint32(200_000) @@ -357,7 +368,7 @@ func TestFunctionsReporting_Report_CallbackGasLimitExceeded(t *testing.T) { func TestFunctionsReporting_Report_DeterministicOrderOfRequests(t *testing.T) { t.Parallel() - plugin, _, codec := preparePlugin(t, 10, 0, 0) + plugin, _, codec := preparePlugin(t, 10, 0) reqId1, reqId2, reqId3 := newRequestID(), newRequestID(), newRequestID() compResult := []byte("aaa") @@ -386,7 +397,7 @@ func TestFunctionsReporting_Report_DeterministicOrderOfRequests(t *testing.T) { func TestFunctionsReporting_Report_IncorrectObservation(t *testing.T) { t.Parallel() - plugin, _, _ := preparePlugin(t, 10, 0, 0) + plugin, _, _ := preparePlugin(t, 10, 0) reqId1 := newRequestID() compResult := []byte("aaa") @@ -414,7 +425,7 @@ func getReportBytes(t *testing.T, codec encoding.ReportCodec, reqs ...functions_ func TestFunctionsReporting_ShouldAcceptFinalizedReport(t *testing.T) { t.Parallel() - plugin, orm, codec := preparePlugin(t, 10, 0, 0) + plugin, orm, codec := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("xxx")) // nonexistent req2 := newRequestWithResult([]byte("abc")) @@ -453,7 +464,7 @@ func TestFunctionsReporting_ShouldAcceptFinalizedReport(t *testing.T) { func TestFunctionsReporting_ShouldTransmitAcceptedReport(t *testing.T) { t.Parallel() - plugin, orm, codec := preparePlugin(t, 10, 0, 0) + plugin, orm, codec := preparePlugin(t, 10, 0) req1 := newRequestWithResult([]byte("xxx")) // nonexistent req2 := newRequestWithResult([]byte("abc")) diff --git a/core/services/ocr2/plugins/median/plugin.go b/core/services/ocr2/plugins/median/plugin.go index 544e75397b5..b78b75cbfcb 100644 --- a/core/services/ocr2/plugins/median/plugin.go +++ b/core/services/ocr2/plugins/median/plugin.go @@ -11,16 +11,15 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/plugins" ) type Plugin struct { - plugins.Base + loop.Plugin stop utils.StopChan } func NewPlugin(lggr logger.Logger) *Plugin { - return &Plugin{Base: plugins.Base{Logger: lggr}, stop: make(utils.StopChan)} + return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(utils.StopChan)} } func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) { diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index ddb521ff9ca..60904b58139 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -13,15 +13,15 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/wsrpc" - "github.com/smartcontractkit/wsrpc/credentials" - "github.com/smartcontractkit/wsrpc/peer" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" - "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/wsrpc" + "github.com/smartcontractkit/wsrpc/credentials" + "github.com/smartcontractkit/wsrpc/peer" + "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -151,15 +151,14 @@ func (node *Node) AddBootstrapJob(t *testing.T, spec string) { func setupNode( t *testing.T, - port int64, + port int, dbName string, - p2pV2Bootstrappers []commontypes.BootstrapperLocator, backend *backends.SimulatedBackend, csaKey csakey.KeyV2, ) (app chainlink.Application, peerID string, clientPubKey credentials.StaticSizedPublicKey, ocr2kb ocr2key.KeyBundle, observedLogs *observer.ObservedLogs) { - k := big.NewInt(port) // keys unique to port + k := big.NewInt(int64(port)) // keys unique to port p2pKey := p2pkey.MustNewV2XXXTestingOnly(k) - rdr := keystest.NewRandReaderFromSeed(port) + rdr := keystest.NewRandReaderFromSeed(int64(port)) ocr2kb = ocr2key.MustNewInsecure(rdr, chaintype.EVM) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} @@ -191,10 +190,6 @@ func setupNode( c.P2P.PeerID = ptr(p2pKey.PeerID()) c.P2P.TraceLogging = ptr(true) - // [P2P.V1] - // Enabled = false - c.P2P.V1.Enabled = ptr(false) - // [P2P.V2] // Enabled = true // AnnounceAddresses = ['$EXT_IP:17775'] @@ -243,7 +238,7 @@ func addV1MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, bidBridge, askBridge, @@ -326,7 +321,7 @@ func addV2MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, serverURL string, serverPubKey, @@ -391,7 +386,7 @@ func addV3MercuryJob( i int, verifierAddress common.Address, bootstrapPeerID string, - bootstrapNodePort int64, + bootstrapNodePort int, bmBridge, bidBridge, askBridge, diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index aab1cadc5a5..e7e059289a2 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -22,17 +22,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/shopspring/decimal" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/wsrpc/credentials" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/wsrpc/credentials" + relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaycodecv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" relaycodecv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" @@ -173,8 +174,8 @@ func TestIntegration_MercuryV1(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19700) - appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", nil, backend, clientCSAKeys[n]) + bootstrapNodePort := freeport.GetOne(t) + appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -183,11 +184,9 @@ func TestIntegration_MercuryV1(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), []commontypes.BootstrapperLocator{ - // Supply the bootstrap IP and port as a V2 peer address - {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, @@ -524,8 +523,8 @@ func TestIntegration_MercuryV2(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(20700) - appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", nil, backend, clientCSAKeys[n]) + bootstrapNodePort := freeport.GetOne(t) + appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -534,11 +533,9 @@ func TestIntegration_MercuryV2(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), []commontypes.BootstrapperLocator{ - // Supply the bootstrap IP and port as a V2 peer address - {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, @@ -802,8 +799,8 @@ func TestIntegration_MercuryV3(t *testing.T) { steve, backend, verifier, verifierAddress := setupBlockchain(t) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(21700) - appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", nil, backend, clientCSAKeys[n]) + bootstrapNodePort := freeport.GetOne(t) + appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n]) bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb} logObservers = append(logObservers, observedLogs) @@ -812,11 +809,9 @@ func TestIntegration_MercuryV3(t *testing.T) { oracles []confighelper.OracleIdentityExtra nodes []Node ) - for i := int64(0); i < int64(n); i++ { - app, peerID, transmitter, kb, observedLogs := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_mercury%d", i), []commontypes.BootstrapperLocator{ - // Supply the bootstrap IP and port as a V2 peer address - {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, backend, clientCSAKeys[i]) + ports := freeport.GetN(t, n) + for i := 0; i < n; i++ { + app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i]) nodes = append(nodes, Node{ app, transmitter, kb, diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index 31fb8ab8c4b..69a3b53c284 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -125,12 +125,6 @@ func NewServices( if err != nil { return nil, errors.WithStack(err) } - return []job.ServiceCtx{ocr2Provider, ocrcommon.NewResultRunSaver( - runResults, - pipelineRunner, - make(chan struct{}), - lggr, - cfg.MaxSuccessfulRuns(), - ), - job.NewServiceAdapter(oracle)}, nil + saver := ocrcommon.NewResultRunSaver(runResults, pipelineRunner, make(chan struct{}), lggr, cfg.MaxSuccessfulRuns()) + return []job.ServiceCtx{ocr2Provider, saver, job.NewServiceAdapter(oracle)}, nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go index 69533e95869..e32c4a0662e 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/log_provider.go @@ -82,7 +82,7 @@ func NewLogProvider( } return &LogProvider{ - logger: logger, + logger: logger.Named("AutomationLogProvider"), logPoller: logPoller, registryAddress: registryAddress, lookbackBlocks: lookbackBlocks, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go index fedad956111..bc30ac781de 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -121,13 +121,12 @@ func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { return r0, r1 } -type mockConstructorTestingTNewRegistry interface { +// NewRegistry creates a new instance of Registry. 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 NewRegistry(t interface { mock.TestingT Cleanup(func()) -} - -// NewRegistry creates a new instance of Registry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRegistry(t mockConstructorTestingTNewRegistry) *Registry { +}) *Registry { mock := &Registry{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go index 3f574158e31..7d1de17a5b0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm20/registry.go @@ -87,7 +87,7 @@ func NewEVMRegistryService(addr common.Address, client evm.Chain, lggr logger.Lo hb: client.HeadBroadcaster(), chHead: make(chan ocr2keepers.BlockKey, 1), }, - lggr: lggr, + lggr: lggr.Named("AutomationRegistry"), poller: client.LogPoller(), addr: addr, client: client.Client(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/abi.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/abi.go new file mode 100644 index 00000000000..0acb59917ac --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/abi.go @@ -0,0 +1,14 @@ +package core + +import ( + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_log_automation" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" +) + +var UtilsABI = types.MustGetABI(automation_utils_2_1.AutomationUtilsABI) +var RegistryABI = types.MustGetABI(iregistry21.IKeeperRegistryMasterABI) +var StreamsCompatibleABI = types.MustGetABI(streams_lookup_compatible_interface.StreamsLookupCompatibleInterfaceABI) +var ILogAutomationABI = types.MustGetABI(i_log_automation.ILogAutomationABI) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go b/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go index 9644f843fe5..40b63611c90 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/core/mocks/upkeep_state_reader.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -48,13 +48,12 @@ func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...str return r0, r1 } -type mockConstructorTestingTNewUpkeepStateReader interface { +// NewUpkeepStateReader creates a new instance of UpkeepStateReader. 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 NewUpkeepStateReader(t interface { mock.TestingT Cleanup(func()) -} - -// NewUpkeepStateReader creates a new instance of UpkeepStateReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewUpkeepStateReader(t mockConstructorTestingTNewUpkeepStateReader) *UpkeepStateReader { +}) *UpkeepStateReader { mock := &UpkeepStateReader{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go index 36435a93bab..578153e07a4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/encoder_test.go @@ -2,26 +2,18 @@ package encoding import ( "math/big" - "strings" "testing" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) func TestReportEncoder_EncodeExtract(t *testing.T) { - keepersABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI)) - assert.Nil(t, err) - utilsABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI)) - assert.Nil(t, err) encoder := reportEncoder{ - packer: NewAbiPacker(keepersABI, utilsABI), + packer: NewAbiPacker(), } tests := []struct { diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index 1f36cadb4d7..217f0dcb571 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -56,4 +56,5 @@ type Packer interface { UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) + DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go index 824a98172bd..9e070b2838c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer.go @@ -8,25 +8,24 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) -var utilsABI = types.MustGetABI(automation_utils_2_1.AutomationUtilsABI) - // triggerWrapper is a wrapper for the different trigger types (log and condition triggers). // NOTE: we use log trigger because it extends condition trigger, type triggerWrapper = automation_utils_2_1.KeeperRegistryBase21LogTrigger type abiPacker struct { - abi abi.ABI - utilsAbi abi.ABI + registryABI abi.ABI + utilsABI abi.ABI + streamsABI abi.ABI } var _ Packer = (*abiPacker)(nil) -func NewAbiPacker(abi abi.ABI, utilsAbi abi.ABI) *abiPacker { - return &abiPacker{abi: abi, utilsAbi: utilsAbi} +func NewAbiPacker() *abiPacker { + return &abiPacker{registryABI: core.RegistryABI, utilsABI: core.UtilsABI, streamsABI: core.StreamsCompatibleABI} } func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) { @@ -37,7 +36,7 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str fmt.Errorf("upkeepId %s failed to decode checkUpkeep result %s: %s", payload.UpkeepID.String(), raw, err) } - out, err := p.abi.Methods["checkUpkeep"].Outputs.UnpackValues(b) + out, err := p.registryABI.Methods["checkUpkeep"].Outputs.UnpackValues(b) if err != nil { // unpack failed, not retryable return GetIneligibleCheckResultWithoutPerformData(payload, UpkeepFailureReasonNone, PackUnpackDecodeFailed, false), @@ -67,11 +66,11 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str } func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { - return p.abi.Pack("getUpkeepPrivilegeConfig", upkeepId) + return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) } func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { - out, err := p.abi.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) + out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) if err != nil { return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) } @@ -82,7 +81,7 @@ func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) } func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (PipelineExecutionState, bool, []byte, uint8, *big.Int, error) { - out, err := p.abi.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) + out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) if err != nil { return PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) } @@ -101,7 +100,7 @@ func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, boo return PackUnpackDecodeFailed, false, err } - out, err := p.abi.Methods["simulatePerformUpkeep"].Outputs.UnpackValues(b) + out, err := p.registryABI.Methods["simulatePerformUpkeep"].Outputs.UnpackValues(b) if err != nil { return PackUnpackDecodeFailed, false, err } @@ -113,7 +112,7 @@ func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, boo func (p *abiPacker) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) { var cfg automation_utils_2_1.LogTriggerConfig - out, err := utilsABI.Methods["_logTriggerConfig"].Inputs.UnpackValues(raw) + out, err := core.UtilsABI.Methods["_logTriggerConfig"].Inputs.UnpackValues(raw) if err != nil { return cfg, fmt.Errorf("%w: unpack _logTriggerConfig return: %s", err, raw) } @@ -127,7 +126,7 @@ func (p *abiPacker) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.Log // PackReport packs the report with abi definitions from the contract. func (p *abiPacker) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) { - bts, err := p.utilsAbi.Methods["_report"].Inputs.Pack(&report) + bts, err := p.utilsABI.Methods["_report"].Inputs.Pack(&report) if err != nil { return nil, fmt.Errorf("%w: failed to pack report", err) } @@ -136,7 +135,7 @@ func (p *abiPacker) PackReport(report automation_utils_2_1.KeeperRegistryBase21R // UnpackReport unpacks the report from the given raw data. func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) { - unpacked, err := p.utilsAbi.Methods["_report"].Inputs.Unpack(raw) + unpacked, err := p.utilsABI.Methods["_report"].Inputs.Unpack(raw) if err != nil { return automation_utils_2_1.KeeperRegistryBase21Report{}, fmt.Errorf("%w: failed to unpack report", err) } @@ -162,6 +161,32 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr return report, nil } +type StreamsLookupError struct { + FeedParamKey string + Feeds []string + TimeParamKey string + Time *big.Int + ExtraData []byte +} + +// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) +func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) { + e := p.streamsABI.Errors["StreamsLookup"] + unpack, err := e.Unpack(data) + if err != nil { + return nil, fmt.Errorf("unpack error: %w", err) + } + errorParameters := unpack.([]interface{}) + + return &StreamsLookupError{ + FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), + Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), + TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), + Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), + ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), + }, nil +} + // GetIneligibleCheckResultWithoutPerformData returns an ineligible check result with ineligibility reason and pipeline execution state but without perform data func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason UpkeepFailureReason, state PipelineExecutionState, retryable bool) ocr2keepers.CheckResult { return ocr2keepers.CheckResult{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go index b333a695bf8..1801b018572 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/packer_test.go @@ -2,12 +2,11 @@ package encoding import ( "encoding/json" + "errors" "fmt" "math/big" - "strings" "testing" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" @@ -16,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" automation21Utils "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) @@ -106,8 +104,7 @@ func TestPacker_PackReport(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - packer, err := newPacker() - assert.NoError(t, err) + packer := NewAbiPacker() bytes, err := packer.PackReport(tc.report) if tc.expectsErr { assert.Error(t, err) @@ -192,8 +189,7 @@ func TestPacker_UnpackCheckResults(t *testing.T) { } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - packer, err := newPacker() - assert.NoError(t, err) + packer := NewAbiPacker() rs, err := packer.UnpackCheckResult(test.Payload, test.RawData) if test.ExpectedError != nil { assert.Equal(t, test.ExpectedError.Error(), err.Error()) @@ -224,8 +220,7 @@ func TestPacker_UnpackPerformResult(t *testing.T) { } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - packer, err := newPacker() - assert.NoError(t, err) + packer := NewAbiPacker() state, rs, err := packer.UnpackPerformResult(test.RawData) assert.Nil(t, err) assert.True(t, rs) @@ -272,8 +267,7 @@ func TestPacker_UnpackCheckCallbackResult(t *testing.T) { } for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - packer, err := newPacker() - assert.NoError(t, err) + packer := NewAbiPacker() state, needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp) @@ -323,8 +317,7 @@ func TestPacker_UnpackLogTriggerConfig(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - packer, err := newPacker() - assert.NoError(t, err) + packer := NewAbiPacker() res, err := packer.UnpackLogTriggerConfig(tc.raw) if tc.errored { assert.Error(t, err) @@ -345,8 +338,7 @@ func TestPacker_PackReport_UnpackReport(t *testing.T) { Triggers: [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}}, PerformDatas: [][]byte{{5, 6, 7, 8}, {1, 2, 3, 4}}, } - packer, err := newPacker() - require.NoError(t, err) + packer := NewAbiPacker() res, err := packer.PackReport(report) require.NoError(t, err) report2, err := packer.UnpackReport(res) @@ -381,8 +373,7 @@ func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - packer, err := newPacker() - require.NoError(t, err, "valid packer required for test") + packer := NewAbiPacker() b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) @@ -425,8 +416,7 @@ func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - packer, err := newPacker() - require.NoError(t, err, "valid packer required for test") + packer := NewAbiPacker() b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) @@ -447,14 +437,40 @@ func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { } } -func newPacker() (*abiPacker, error) { - keepersABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI)) - if err != nil { - return nil, err +func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { + tests := []struct { + name string + data []byte + expected *StreamsLookupError + state PipelineExecutionState + err error + }{ + { + name: "success - decode to streams lookup", + data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + expected: &StreamsLookupError{ + FeedParamKey: "feedIdHex", + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: "blockNumber", + Time: big.NewInt(37969589), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + }, + { + name: "failure - unpack error", + data: []byte{1, 2, 3, 4}, + err: errors.New("unpack error: invalid data for unpacking"), + }, } - utilsABI, err := abi.JSON(strings.NewReader(automation21Utils.AutomationUtilsABI)) - if err != nil { - return nil, err + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + packer := NewAbiPacker() + fl, err := packer.DecodeStreamsLookupRequest(tt.data) + assert.Equal(t, tt.expected, fl) + if tt.err != nil { + assert.Equal(t, tt.err.Error(), err.Error()) + } + }) } - return NewAbiPacker(keepersABI, utilsABI), nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go index 4b3fa8cb404..38342550c58 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/factory.go @@ -3,7 +3,6 @@ package logprovider import ( "time" - "github.com/ethereum/go-ethereum/accounts/abi" "golang.org/x/time/rate" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -14,9 +13,9 @@ import ( // New creates a new log event provider and recoverer. // using default values for the options. -func New(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, utilsABI abi.ABI, stateStore core.UpkeepStateReader, finalityDepth uint32) (LogEventProvider, LogRecoverer) { +func New(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore core.UpkeepStateReader, finalityDepth uint32) (LogEventProvider, LogRecoverer) { filterStore := NewUpkeepFilterStore() - packer := NewLogEventsPacker(utilsABI) + packer := NewLogEventsPacker() opts := NewOptions(int64(finalityDepth)) provider := NewLogProvider(lggr, poller, packer, filterStore, opts) recoverer := NewLogRecoverer(lggr, poller, c, stateStore, packer, filterStore, opts) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index b5f229f6015..506dcb9ea33 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -5,11 +5,9 @@ import ( "errors" "fmt" "math/big" - "strings" "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -28,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -54,9 +51,9 @@ func TestIntegration_LogEventProvider(t *testing.T) { opts := logprovider.NewOptions(200) opts.ReadInterval = time.Second / 2 - lp, ethClient, utilsABI := setupDependencies(t, db, backend) + lp, ethClient := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - provider, _ := setup(logger.TestLogger(t), lp, nil, utilsABI, nil, filterStore, &opts) + provider, _ := setup(logger.TestLogger(t), lp, nil, nil, filterStore, &opts) logProvider := provider.(logprovider.LogEventProviderTest) n := 10 @@ -95,10 +92,8 @@ func TestIntegration_LogEventProvider(t *testing.T) { t.Log("restarting log provider") // assuming that our service was closed and restarted, // we should be able to backfill old logs and fetch new ones - logDataABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI)) - require.NoError(t, err) filterStore := logprovider.NewUpkeepFilterStore() - logProvider2 := logprovider.NewLogProvider(logger.TestLogger(t), lp, logprovider.NewLogEventsPacker(logDataABI), filterStore, opts) + logProvider2 := logprovider.NewLogProvider(logger.TestLogger(t), lp, logprovider.NewLogEventsPacker(), filterStore, opts) poll(backend.Commit()) go func() { @@ -111,7 +106,7 @@ func TestIntegration_LogEventProvider(t *testing.T) { // re-register filters for i, id := range ids { - err = logProvider2.RegisterFilter(ctx, logprovider.FilterOptions{ + err := logProvider2.RegisterFilter(ctx, logprovider.FilterOptions{ UpkeepID: id, TriggerConfig: newPlainLogTriggerConfig(addrs[i]), // using block number at which the upkeep was registered, @@ -144,9 +139,9 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { opts := &logprovider.LogTriggersOptions{ ReadInterval: time.Second / 2, } - lp, ethClient, utilsABI := setupDependencies(t, db, backend) + lp, ethClient := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - provider, _ := setup(logger.TestLogger(t), lp, nil, utilsABI, nil, filterStore, opts) + provider, _ := setup(logger.TestLogger(t), lp, nil, nil, filterStore, opts) logProvider := provider.(logprovider.LogEventProviderTest) backend.Commit() @@ -217,9 +212,9 @@ func TestIntegration_LogEventProvider_Backfill(t *testing.T) { opts := logprovider.NewOptions(200) opts.ReadInterval = time.Second / 4 - lp, ethClient, utilsABI := setupDependencies(t, db, backend) + lp, ethClient := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - provider, _ := setup(logger.TestLogger(t), lp, nil, utilsABI, nil, filterStore, &opts) + provider, _ := setup(logger.TestLogger(t), lp, nil, nil, filterStore, &opts) logProvider := provider.(logprovider.LogEventProviderTest) n := 10 @@ -276,9 +271,9 @@ func TestIntegration_LogEventProvider_RateLimit(t *testing.T) { stopMining() _ = db.Close() } - lp, ethClient, utilsABI := setupDependencies(t, db, backend) + lp, ethClient := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - provider, _ := setup(logger.TestLogger(t), lp, nil, utilsABI, nil, filterStore, opts) + provider, _ := setup(logger.TestLogger(t), lp, nil, nil, filterStore, opts) logProvider := provider.(logprovider.LogEventProviderTest) backend.Commit() lp.PollAndSaveLogs(ctx, 1) // Ensure log poller has a latest block @@ -476,14 +471,14 @@ func TestIntegration_LogRecoverer_Backfill(t *testing.T) { ReadInterval: time.Second / 4, LookbackBlocks: lookbackBlocks, } - lp, ethClient, utilsABI := setupDependencies(t, db, backend) + lp, ethClient := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() origDefaultRecoveryInterval := logprovider.RecoveryInterval logprovider.RecoveryInterval = time.Millisecond * 200 defer func() { logprovider.RecoveryInterval = origDefaultRecoveryInterval }() - provider, recoverer := setup(logger.TestLogger(t), lp, nil, utilsABI, &mockUpkeepStateStore{}, filterStore, opts) + provider, recoverer := setup(logger.TestLogger(t), lp, nil, &mockUpkeepStateStore{}, filterStore, opts) logProvider := provider.(logprovider.LogEventProviderTest) backend.Commit() @@ -662,21 +657,17 @@ func newPlainLogTriggerConfig(upkeepAddr common.Address) logprovider.LogTriggerC } } -func setupDependencies(t *testing.T, db *sqlx.DB, backend *backends.SimulatedBackend) (logpoller.LogPollerTest, *evmclient.SimulatedBackendClient, abi.ABI) { +func setupDependencies(t *testing.T, db *sqlx.DB, backend *backends.SimulatedBackend) (logpoller.LogPollerTest, *evmclient.SimulatedBackendClient) { ethClient := evmclient.NewSimulatedBackendClient(t, backend, big.NewInt(1337)) pollerLggr := logger.TestLogger(t) pollerLggr.SetLogLevel(zapcore.WarnLevel) lorm := logpoller.NewORM(big.NewInt(1337), db, pollerLggr, pgtest.NewQConfig(false)) - lp := logpoller.NewLogPoller(lorm, ethClient, pollerLggr, 100*time.Millisecond, 1, 2, 2, 1000) - - utilsABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI)) - require.NoError(t, err) - - return lp, ethClient, utilsABI + lp := logpoller.NewLogPoller(lorm, ethClient, pollerLggr, 100*time.Millisecond, false, 1, 2, 2, 1000) + return lp, ethClient } -func setup(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, utilsABI abi.ABI, stateStore kevmcore.UpkeepStateReader, filterStore logprovider.UpkeepFilterStore, opts *logprovider.LogTriggersOptions) (logprovider.LogEventProvider, logprovider.LogRecoverer) { - packer := logprovider.NewLogEventsPacker(utilsABI) +func setup(lggr logger.Logger, poller logpoller.LogPoller, c client.Client, stateStore kevmcore.UpkeepStateReader, filterStore logprovider.UpkeepFilterStore, opts *logprovider.LogTriggersOptions) (logprovider.LogEventProvider, logprovider.LogRecoverer) { + packer := logprovider.NewLogEventsPacker() if opts == nil { o := logprovider.NewOptions(200) opts = &o diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go index 538839b011c..655d7dacfe6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/log_packer.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) type LogDataPacker interface { @@ -17,8 +18,8 @@ type logEventsPacker struct { abi abi.ABI } -func NewLogEventsPacker(utilsABI abi.ABI) *logEventsPacker { - return &logEventsPacker{abi: utilsABI} +func NewLogEventsPacker() *logEventsPacker { + return &logEventsPacker{abi: core.UtilsABI} } func (p *logEventsPacker) PackLogData(log logpoller.Log) ([]byte, error) { @@ -26,7 +27,7 @@ func (p *logEventsPacker) PackLogData(log logpoller.Log) ([]byte, error) { for _, topic := range log.GetTopics() { topics = append(topics, topic) } - b, err := p.abi.Pack("_log", &automation_utils_2_1.Log{ + b, err := p.abi.Methods["_log"].Inputs.Pack(&automation_utils_2_1.Log{ Index: big.NewInt(log.LogIndex), Timestamp: big.NewInt(log.BlockTimestamp.Unix()), TxHash: log.TxHash, @@ -39,5 +40,5 @@ func (p *logEventsPacker) PackLogData(log logpoller.Log) ([]byte, error) { if err != nil { return nil, err } - return b[4:], nil + return b, nil } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go index 2f61d55a2df..53d347b1c06 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -39,13 +39,12 @@ func (_m *HttpClient) Do(req *http.Request) (*http.Response, error) { return r0, r1 } -type mockConstructorTestingTNewHttpClient interface { +// NewHttpClient creates a new instance of HttpClient. 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 NewHttpClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewHttpClient creates a new instance of HttpClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHttpClient(t mockConstructorTestingTNewHttpClient) *HttpClient { +}) *HttpClient { mock := &HttpClient{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go index 1827d4cb57f..a3cbd772b1d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/mocks/registry.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -22,23 +22,21 @@ type Registry struct { } // CheckCallback provides a mock function with given fields: opts, id, values, extraData -func (_m *Registry) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { +func (_m *Registry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error) { ret := _m.Called(opts, id, values, extraData) - var r0 *types.Transaction + var r0 i_keeper_registry_master_wrapper_2_1.CheckCallback var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, [][]byte, []byte) (*types.Transaction, error)); ok { + if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, [][]byte, []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error)); ok { return rf(opts, id, values, extraData) } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, [][]byte, []byte) *types.Transaction); ok { + if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, [][]byte, []byte) i_keeper_registry_master_wrapper_2_1.CheckCallback); ok { r0 = rf(opts, id, values, extraData) } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } + r0 = ret.Get(0).(i_keeper_registry_master_wrapper_2_1.CheckCallback) } - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, [][]byte, []byte) error); ok { + if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int, [][]byte, []byte) error); ok { r1 = rf(opts, id, values, extraData) } else { r1 = ret.Error(1) @@ -199,13 +197,12 @@ func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { return r0, r1 } -type mockConstructorTestingTNewRegistry interface { +// NewRegistry creates a new instance of Registry. 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 NewRegistry(t interface { mock.TestingT Cleanup(func()) -} - -// NewRegistry creates a new instance of Registry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRegistry(t mockConstructorTestingTNewRegistry) *Registry { +}) *Registry { mock := &Registry{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 590e5138b3e..1cad587e635 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -15,9 +15,10 @@ import ( coreTypes "github.com/ethereum/go-ethereum/core/types" "github.com/patrickmn/go-cache" "github.com/pkg/errors" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "go.uber.org/multierr" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -62,7 +63,7 @@ type Registry interface { GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) - CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*coreTypes.Transaction, error) + CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) ParseLog(log coreTypes.Log) (generated.AbigenLog, error) } @@ -75,7 +76,6 @@ func NewEvmRegistry( lggr logger.Logger, addr common.Address, client evm.Chain, - streamsLookupCompatibleABI, keeperRegistryABI abi.ABI, registry *iregistry21.IKeeperRegistryMaster, mc *models.MercuryCredentials, al ActiveUpkeepList, @@ -87,20 +87,20 @@ func NewEvmRegistry( return &EvmRegistry{ ctx: context.Background(), threadCtrl: utils.NewThreadControl(), - lggr: lggr.Named("EvmRegistry"), + lggr: lggr.Named(RegistryServiceName), poller: client.LogPoller(), addr: addr, client: client.Client(), logProcessed: make(map[string]bool), registry: registry, - abi: keeperRegistryABI, + abi: core.RegistryABI, active: al, packer: packer, headFunc: func(ocr2keepers.BlockKey) {}, chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ cred: mc, - abi: streamsLookupCompatibleABI, + abi: core.StreamsCompatibleABI, allowListCache: cache.New(defaultAllowListExpiration, allowListCleanupInterval), }, hc: http.DefaultClient, @@ -145,8 +145,6 @@ type EvmRegistry struct { lastPollBlock int64 ctx context.Context headFunc func(ocr2keepers.BlockKey) - runState int - runError error mercury *MercuryConfig hc HttpClient bs *BlockSubscriber @@ -299,11 +297,11 @@ func (r *EvmRegistry) refreshLogTriggerUpkeepsBatch(logTriggerIDs []*big.Int) er logTriggerHashes = append(logTriggerHashes, common.BigToHash(id)) } - unpausedLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepUnpaused{}.Topic(), r.addr, 1, logTriggerHashes, int(r.finalityDepth), pg.WithParentCtx(r.ctx)) + unpausedLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepUnpaused{}.Topic(), r.addr, 1, logTriggerHashes, logpoller.Confirmations(r.finalityDepth), pg.WithParentCtx(r.ctx)) if err != nil { return err } - configSetLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{}.Topic(), r.addr, 1, logTriggerHashes, int(r.finalityDepth), pg.WithParentCtx(r.ctx)) + configSetLogs, err := r.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{}.Topic(), r.addr, 1, logTriggerHashes, logpoller.Confirmations(r.finalityDepth), pg.WithParentCtx(r.ctx)) if err != nil { return err } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index ee213643194..5ea2bdc6670 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -204,14 +204,14 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { type mockLogPoller struct { logpoller.LogPoller GetBlocksRangeFn func(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]logpoller.LogPollerBlock, error) - IndexedLogsFn func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) + IndexedLogsFn func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) } func (p *mockLogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]logpoller.LogPollerBlock, error) { return p.GetBlocksRangeFn(ctx, numbers, qopts...) } -func (p *mockLogPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { +func (p *mockLogPoller) IndexedLogs(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return p.IndexedLogsFn(eventSig, address, topicIndex, topicValues, confs, qopts...) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go index b6b123de485..0cd5ecd2592 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_test.go @@ -220,7 +220,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { if eventSig == (iregistry21.IKeeperRegistryMasterUpkeepUnpaused{}.Topic()) { return nil, errors.New("indexed logs boom") } @@ -245,7 +245,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { if eventSig == (iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{}.Topic()) { return nil, errors.New("indexed logs boom") } @@ -270,7 +270,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ {}, }, nil @@ -302,7 +302,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { BlockNumber: 1, @@ -356,7 +356,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { BlockNumber: 2, @@ -408,7 +408,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { BlockNumber: 2, @@ -462,7 +462,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { }, }, poller: &mockLogPoller{ - IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs int, qopts ...pg.QOpt) ([]logpoller.Log, error) { + IndexedLogsFn: func(eventSig common.Hash, address common.Address, topicIndex int, topicValues []common.Hash, confs logpoller.Confirmations, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { BlockNumber: 2, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go index 79a9da0c68c..f9d3dd92591 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/services.go @@ -2,9 +2,7 @@ package evm import ( "fmt" - "strings" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -13,9 +11,7 @@ import ( "github.com/smartcontractkit/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" @@ -39,18 +35,6 @@ type AutomationServices interface { } func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, lggr logger.Logger, db *sqlx.DB, dbCfg pg.QConfig) (AutomationServices, error) { - streamsLookupCompatibleABI, err := abi.JSON(strings.NewReader(streams_lookup_compatible_interface.StreamsLookupCompatibleInterfaceABI)) - if err != nil { - return nil, fmt.Errorf("%w: %s", ErrABINotParsable, err) - } - keeperRegistryABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI)) - if err != nil { - return nil, fmt.Errorf("%w: %s", ErrABINotParsable, err) - } - utilsABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI)) - if err != nil { - return nil, fmt.Errorf("%w: %s", ErrABINotParsable, err) - } registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) if err != nil { return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) @@ -66,7 +50,7 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k services := new(automationServices) services.transmitEventProvider = transmitEventProvider - packer := encoding.NewAbiPacker(keeperRegistryABI, utilsABI) + packer := encoding.NewAbiPacker() services.encoder = encoding.NewReportEncoder(packer) finalityDepth := client.Config().EVM().FinalityDepth() @@ -75,7 +59,7 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k scanner := upkeepstate.NewPerformedEventsScanner(lggr, client.LogPoller(), addr, finalityDepth) services.upkeepState = upkeepstate.NewUpkeepStateStore(orm, lggr, scanner) - logProvider, logRecoverer := logprovider.New(lggr, client.LogPoller(), client.Client(), utilsABI, services.upkeepState, finalityDepth) + logProvider, logRecoverer := logprovider.New(lggr, client.LogPoller(), client.Client(), services.upkeepState, finalityDepth) services.logProvider = logProvider services.logRecoverer = logRecoverer services.blockSub = NewBlockSubscriber(client.HeadBroadcaster(), client.LogPoller(), finalityDepth, lggr) @@ -85,8 +69,8 @@ func New(addr common.Address, client evm.Chain, mc *models.MercuryCredentials, k al := NewActiveUpkeepList() services.payloadBuilder = NewPayloadBuilder(al, logRecoverer, lggr) - services.reg = NewEvmRegistry(lggr, addr, client, streamsLookupCompatibleABI, - keeperRegistryABI, registryContract, mc, al, services.logProvider, + services.reg = NewEvmRegistry(lggr, addr, client, + registryContract, mc, al, services.logProvider, packer, services.blockSub, finalityDepth) services.upkeepProvider = NewUpkeepProvider(al, services.blockSub, client.LogPoller()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go index 2155b383002..6f2594b6c38 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup.go @@ -18,7 +18,6 @@ import ( "time" "github.com/avast/retry-go/v4" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" @@ -29,30 +28,27 @@ import ( ) const ( - applicationJson = "application/json" - blockNumber = "blockNumber" // valid for v0.2 - feedIDs = "feedIDs" // valid for v0.3 - feedIdHex = "feedIdHex" // valid for v0.2 - headerAuthorization = "Authorization" - headerContentType = "Content-Type" - headerTimestamp = "X-Authorization-Timestamp" - headerSignature = "X-Authorization-Signature-SHA256" - headerUpkeepId = "X-Authorization-Upkeep-Id" - mercuryPathV02 = "/client?" // only used to access mercury v0.2 server - mercuryBatchPathV03 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server - retryDelay = 500 * time.Millisecond - timestamp = "timestamp" // valid for v0.3 - totalAttempt = 3 + applicationJson = "application/json" + blockNumber = "blockNumber" // valid for v0.2 + feedIDs = "feedIDs" // valid for v0.3 + feedIdHex = "feedIdHex" // valid for v0.2 + headerAuthorization = "Authorization" + headerContentType = "Content-Type" + headerTimestamp = "X-Authorization-Timestamp" + headerSignature = "X-Authorization-Signature-SHA256" + headerUpkeepId = "X-Authorization-Upkeep-Id" + mercuryPathV02 = "/client?" // only used to access mercury v0.2 server + mercuryBatchPathV03 = "/api/v1/reports/bulk?" // only used to access mercury v0.3 server + mercuryBatchPathV03BlockNumber = "/api/v1gmx/reports/bulk?" // only used to access mercury v0.3 server with blockNumber + retryDelay = 500 * time.Millisecond + timestamp = "timestamp" // valid for v0.3 + totalAttempt = 3 ) type StreamsLookup struct { - feedParamKey string - feeds []string - timeParamKey string - time *big.Int - extraData []byte - upkeepId *big.Int - block uint64 + *encoding.StreamsLookupError + upkeepId *big.Int + block uint64 } // MercuryV02Response represents a JSON structure used by Mercury v0.2 @@ -66,10 +62,10 @@ type MercuryV03Response struct { } type MercuryV03Report struct { - FeedID []byte `json:"feedID"` // feed id in hex + FeedID string `json:"feedID"` // feed id in hex encoded ValidFromTimestamp uint32 `json:"validFromTimestamp"` ObservationsTimestamp uint32 `json:"observationsTimestamp"` - FullReport []byte `json:"fullReport"` // the actual mercury report of this feed, can be sent to verifier + FullReport string `json:"fullReport"` // the actual hex encoded mercury report of this feed, can be sent to verifier } type MercuryData struct { @@ -101,25 +97,26 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they // tried to call mercury - lggr.Infof("at block %d upkeep %s trying to decodeStreamsLookup performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) - l, err := r.decodeStreamsLookup(res.PerformData) + lggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) + streamsLookupErr, err := r.packer.DecodeStreamsLookupRequest(res.PerformData) if err != nil { - lggr.Warnf("at block %d upkeep %s decodeStreamsLookup failed: %v", block, upkeepId, err) + lggr.Debugf("at block %d upkeep %s DecodeStreamsLookupRequest failed: %v", block, upkeepId, err) // user contract did not revert with StreamsLookup error continue } + l := &StreamsLookup{StreamsLookupError: streamsLookupErr} if r.mercury.cred == nil { lggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) continue } - if len(l.feeds) == 0 { + if len(l.Feeds) == 0 { checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) - lggr.Warnf("at block %s upkeep %s has empty feeds array", block, upkeepId) + lggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) continue } // mercury permission checking for v0.3 is done by mercury server - if l.feedParamKey == feedIdHex && l.timeParamKey == blockNumber { + if l.FeedParamKey == feedIdHex && l.TimeParamKey == blockNumber { // check permission on the registry for mercury v0.2 opts := r.buildCallOpts(ctx, block) state, reason, retryable, allowed, err := r.allowedToUseMercury(opts, upkeepId.BigInt()) @@ -132,13 +129,13 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep } if !allowed { - lggr.Warnf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) + lggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonMercuryAccessNotAllowed) continue } - } else if l.feedParamKey != feedIDs || l.timeParamKey != timestamp { + } else if l.FeedParamKey != feedIDs { // if mercury version cannot be determined, set failure reason - lggr.Warnf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) + lggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) continue } @@ -147,7 +144,7 @@ func (r *EvmRegistry) streamsLookup(ctx context.Context, checkResults []ocr2keep // the block here is exclusively used to call checkCallback at this block, not to be confused with the block number // in the revert for mercury v0.2, which is denoted by time in the struct bc starting from v0.3, only timestamp will be supported l.block = uint64(block.Int64()) - lggr.Infof("at block %d upkeep %s decodeStreamsLookup feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, l.feedParamKey, l.timeParamKey, l.feeds, l.time, hexutil.Encode(l.extraData)) + lggr.Infof("at block %d upkeep %s DecodeStreamsLookupRequest feedKey=%s timeKey=%s feeds=%v time=%s extraData=%s", block, upkeepId, l.FeedParamKey, l.TimeParamKey, l.Feeds, l.Time, hexutil.Encode(l.ExtraData)) lookups[i] = l } @@ -260,26 +257,8 @@ func (r *EvmRegistry) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } -// decodeStreamsLookup decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) -func (r *EvmRegistry) decodeStreamsLookup(data []byte) (*StreamsLookup, error) { - e := r.mercury.abi.Errors["StreamsLookup"] - unpack, err := e.Unpack(data) - if err != nil { - return nil, fmt.Errorf("unpack error: %w", err) - } - errorParameters := unpack.([]interface{}) - - return &StreamsLookup{ - feedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), - feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), - timeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), - time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), - extraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), - }, nil -} - func (r *EvmRegistry) checkCallback(ctx context.Context, values [][]byte, lookup *StreamsLookup) (encoding.PipelineExecutionState, bool, hexutil.Bytes, error) { - payload, err := r.abi.Pack("checkCallback", lookup.upkeepId, values, lookup.extraData) + payload, err := r.abi.Pack("checkCallback", lookup.upkeepId, values, lookup.ExtraData) if err != nil { return encoding.PackUnpackDecodeFailed, false, nil, err } @@ -301,28 +280,28 @@ func (r *EvmRegistry) checkCallback(ctx context.Context, values [][]byte, lookup // doMercuryRequest sends requests to Mercury API to retrieve mercury data. func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, lggr logger.Logger) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, error) { var isMercuryV03 bool - resultLen := len(sl.feeds) + resultLen := len(sl.Feeds) ch := make(chan MercuryData, resultLen) - if len(sl.feeds) == 0 { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.feedParamKey, sl.timeParamKey, sl.feeds) + if len(sl.Feeds) == 0 { + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) } - if sl.feedParamKey == feedIdHex && sl.timeParamKey == blockNumber { + if sl.FeedParamKey == feedIdHex && sl.TimeParamKey == blockNumber { // only mercury v0.2 - for i := range sl.feeds { + for i := range sl.Feeds { go r.singleFeedRequest(ctx, ch, i, sl, lggr) } - } else if sl.feedParamKey == feedIDs && sl.timeParamKey == timestamp { + } else if sl.FeedParamKey == feedIDs { // only mercury v0.3 resultLen = 1 isMercuryV03 = true ch = make(chan MercuryData, resultLen) go r.multiFeedsRequest(ctx, ch, sl, lggr) } else { - return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.feedParamKey, sl.timeParamKey, sl.feeds) + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", sl.FeedParamKey, sl.TimeParamKey, sl.Feeds) } var reqErr error - results := make([][]byte, len(sl.feeds)) + results := make([][]byte, len(sl.Feeds)) retryable := true allSuccess := true // in v0.2, use the last execution error as the state, if no execution errors, state will be no error @@ -351,12 +330,12 @@ func (r *EvmRegistry) doMercuryRequest(ctx context.Context, sl *StreamsLookup, l // singleFeedRequest sends a v0.2 Mercury request for a single feed report. func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryData, index int, sl *StreamsLookup, lggr logger.Logger) { q := url.Values{ - sl.feedParamKey: {sl.feeds[index]}, - sl.timeParamKey: {sl.time.String()}, + sl.FeedParamKey: {sl.Feeds[index]}, + sl.TimeParamKey: {sl.Time.String()}, } mercuryURL := r.mercury.cred.LegacyURL reqUrl := fmt.Sprintf("%s%s%s", mercuryURL, mercuryPathV02, q.Encode()) - lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), sl.feeds[index], reqUrl) + lggr.Debugf("request URL for upkeep %s feed %s: %s", sl.upkeepId.String(), sl.Feeds[index], reqUrl) req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) if err != nil { @@ -380,7 +359,7 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa retryable = false resp, err1 := r.hc.Do(req) if err1 != nil { - lggr.Warnf("at block %s upkeep %s GET request fails for feed %s: %v", sl.time.String(), sl.upkeepId.String(), sl.feeds[index], err1) + lggr.Warnf("at block %s upkeep %s GET request fails for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), sl.Feeds[index], err1) retryable = true state = encoding.MercuryFlakyFailure return err1 @@ -400,29 +379,29 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa } if resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusInternalServerError { - lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, sl.feeds[index]) + lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, sl.Feeds[index]) retryable = true state = encoding.MercuryFlakyFailure return errors.New(strconv.FormatInt(int64(resp.StatusCode), 10)) } else if resp.StatusCode != http.StatusOK { retryable = false state = encoding.InvalidMercuryRequest - return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, sl.feeds[index]) + return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, sl.Feeds[index]) } - lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.2 with BODY=%s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) var m MercuryV02Response err1 = json.Unmarshal(body, &m) if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV02Response for feed %s: %v", sl.time.String(), sl.upkeepId.String(), sl.feeds[index], err1) + lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV02Response for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), sl.Feeds[index], err1) retryable = false state = encoding.MercuryUnmarshalError return err1 } blobBytes, err1 := hexutil.Decode(m.ChainlinkBlob) if err1 != nil { - lggr.Warnf("at block %s upkeep %s failed to decode chainlinkBlob %s for feed %s: %v", sl.time.String(), sl.upkeepId.String(), m.ChainlinkBlob, sl.feeds[index], err1) + lggr.Warnf("at block %s upkeep %s failed to decode chainlinkBlob %s for feed %s: %v", sl.Time.String(), sl.upkeepId.String(), m.ChainlinkBlob, sl.Feeds[index], err1) retryable = false state = encoding.InvalidMercuryResponse return err1 @@ -449,7 +428,7 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa Index: index, Bytes: [][]byte{}, Retryable: retryable, - Error: fmt.Errorf("failed to request feed for %s: %w", sl.feeds[index], retryErr), + Error: fmt.Errorf("failed to request feed for %s: %w", sl.Feeds[index], retryErr), State: state, } ch <- md @@ -460,11 +439,15 @@ func (r *EvmRegistry) singleFeedRequest(ctx context.Context, ch chan<- MercuryDa func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryData, sl *StreamsLookup, lggr logger.Logger) { // this won't work bc q.Encode() will encode commas as '%2C' but the server is strictly expecting a comma separated list //q := url.Values{ - // feedIDs: {strings.Join(sl.feeds, ",")}, - // timestamp: {sl.time.String()}, + // feedIDs: {strings.Join(sl.Feeds, ",")}, + // timestamp: {sl.Time.String()}, //} - params := fmt.Sprintf("%s=%s&%s=%s", feedIDs, strings.Join(sl.feeds, ","), timestamp, sl.time.String()) - reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, mercuryBatchPathV03, params) + params := fmt.Sprintf("%s=%s&%s=%s", feedIDs, strings.Join(sl.Feeds, ","), sl.TimeParamKey, sl.Time.String()) + batchPathV03 := mercuryBatchPathV03 + if sl.TimeParamKey == blockNumber { + batchPathV03 = mercuryBatchPathV03BlockNumber + } + reqUrl := fmt.Sprintf("%s%s%s", r.mercury.cred.URL, batchPathV03, params) lggr.Debugf("request URL for upkeep %s userId %s: %s", sl.upkeepId.String(), r.mercury.cred.Username, reqUrl) req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) @@ -474,7 +457,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa } ts := time.Now().UTC().UnixMilli() - signature := r.generateHMAC(http.MethodGet, mercuryBatchPathV03+params, []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) + signature := r.generateHMAC(http.MethodGet, batchPathV03+params, []byte{}, r.mercury.cred.Username, r.mercury.cred.Password, ts) req.Header.Set(headerContentType, applicationJson) // username here is often referred to as user id req.Header.Set(headerAuthorization, r.mercury.cred.Username) @@ -493,7 +476,7 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa retryable = false resp, err1 := r.hc.Do(req) if err1 != nil { - lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) retryable = true state = encoding.MercuryFlakyFailure return err1 @@ -512,15 +495,15 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa return err1 } - lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + lggr.Infof("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) if resp.StatusCode == http.StatusUnauthorized { retryable = false state = encoding.UpkeepNotAuthorized - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) } else if resp.StatusCode == http.StatusBadRequest { retryable = false state = encoding.InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3 with message: %s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, string(body)) } else if resp.StatusCode == http.StatusInternalServerError { retryable = true state = encoding.MercuryFlakyFailure @@ -528,34 +511,43 @@ func (r *EvmRegistry) multiFeedsRequest(ctx context.Context, ch chan<- MercuryDa } else if resp.StatusCode == 420 { // in 0.3, this will happen when missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds retryable = false - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + state = encoding.InvalidMercuryRequest + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) } else if resp.StatusCode != http.StatusOK { retryable = false state = encoding.InvalidMercuryRequest - return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.time.String(), sl.upkeepId.String(), resp.StatusCode) + return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode) } - lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) + lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.Time.String(), sl.upkeepId.String(), resp.StatusCode, hexutil.Encode(body)) var response MercuryV03Response err1 = json.Unmarshal(body, &response) if err1 != nil { - lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.time.String(), sl.upkeepId.String(), err1) + lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.upkeepId.String(), err1) retryable = false state = encoding.MercuryUnmarshalError return err1 } // in v0.3, if some feeds are not available, the server will only return available feeds, but we need to make sure ALL feeds are retrieved before calling user contract // hence, retry in this case. retry will help when we send a very new timestamp and reports are not yet generated - if len(response.Reports) != len(sl.feeds) { + if len(response.Reports) != len(sl.Feeds) { // TODO: AUTO-5044: calculate what reports are missing and log a warning + lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server retruned 200 status with %d reports while we requested %d feeds, treating as 404 (not found) and retrying", sl.Time.String(), sl.upkeepId.String(), len(response.Reports), len(sl.Feeds)) retryable = true state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", http.StatusNotFound) } var reportBytes [][]byte for _, rsp := range response.Reports { - reportBytes = append(reportBytes, rsp.FullReport) + b, err := hexutil.Decode(rsp.FullReport) + if err != nil { + lggr.Warnf("at timestamp %s upkeep %s failed to decode reportBlob %s: %v", sl.Time.String(), sl.upkeepId.String(), rsp.FullReport, err) + retryable = false + state = encoding.InvalidMercuryResponse + return err + } + reportBytes = append(reportBytes, b) } ch <- MercuryData{ Index: 0, diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go index 42aeecb64f6..6f7065ef875 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/streams_lookup_test.go @@ -27,7 +27,6 @@ import ( evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -40,8 +39,6 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { addr := common.HexToAddress("0x6cA639822c6C241Fa9A7A6b5032F6F7F1C513CAD") keeperRegistryABI, err := abi.JSON(strings.NewReader(i_keeper_registry_master_wrapper_2_1.IKeeperRegistryMasterABI)) require.Nil(t, err, "need registry abi") - utilsABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI)) - require.Nil(t, err, "need utils abi") streamsLookupCompatibleABI, err := abi.JSON(strings.NewReader(streams_lookup_compatible_interface.StreamsLookupCompatibleInterfaceABI)) require.Nil(t, err, "need mercury abi") var logPoller logpoller.LogPoller @@ -58,7 +55,7 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { registry: mockReg, abi: keeperRegistryABI, active: NewActiveUpkeepList(), - packer: encoding.NewAbiPacker(keeperRegistryABI, utilsABI), + packer: encoding.NewAbiPacker(), headFunc: func(ocr2keepers.BlockKey) {}, chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ @@ -95,6 +92,7 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { cachedAdminCfg bool hasError bool hasPermission bool + v3 bool }{ { name: "success - happy path no cache", @@ -130,6 +128,41 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { }, hasPermission: true, }, + { + name: "success - happy path no cache - v0.3", + input: []ocr2keepers.CheckResult{ + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000766656564494473000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + blobs: map[string]string{ + "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", + "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", + }, + cachedAdminCfg: false, + extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), + callbackNeeded: true, + checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), + }, + }, + hasPermission: true, + v3: true, + }, { name: "skip - failure reason is insufficient balance", input: []ocr2keepers.CheckResult{ @@ -212,29 +245,43 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { } if len(tt.blobs) > 0 { - hc := mocks.NewHttpClient(t) - mr1 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]} - b1, err := json.Marshal(mr1) - assert.Nil(t, err) - resp1 := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b1)), - } - mr2 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]} - b2, err := json.Marshal(mr2) - assert.Nil(t, err) - resp2 := &http.Response{ - StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewReader(b2)), - } - hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { - return strings.Contains(req.URL.String(), "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000") - })).Return(resp2, nil).Once() + if tt.v3 { + hc := mocks.NewHttpClient(t) + mr1 := MercuryV03Response{ + Reports: []MercuryV03Report{{FullReport: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]}, {FullReport: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]}}} + b1, err := json.Marshal(mr1) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b1)), + } + hc.On("Do", mock.Anything).Return(resp1, nil).Once() + r.hc = hc + } else { + hc := mocks.NewHttpClient(t) + mr1 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"]} + b1, err := json.Marshal(mr1) + assert.Nil(t, err) + resp1 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b1)), + } + mr2 := MercuryV02Response{ChainlinkBlob: tt.blobs["0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"]} + b2, err := json.Marshal(mr2) + assert.Nil(t, err) + resp2 := &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader(b2)), + } + hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { + return strings.Contains(req.URL.String(), "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000") + })).Return(resp2, nil).Once() - hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { - return strings.Contains(req.URL.String(), "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000") - })).Return(resp1, nil).Once() - r.hc = hc + hc.On("Do", mock.MatchedBy(func(req *http.Request) bool { + return strings.Contains(req.URL.String(), "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000") + })).Return(resp1, nil).Once() + r.hc = hc + } } if tt.callbackNeeded { @@ -257,44 +304,6 @@ func TestEvmRegistry_StreamsLookup(t *testing.T) { } } -func TestEvmRegistry_DecodeStreamsLookup(t *testing.T) { - tests := []struct { - name string - data []byte - expected *StreamsLookup - state encoding.PipelineExecutionState - err error - }{ - { - name: "success - decode to streams lookup", - data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - expected: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(37969589), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - }, - { - name: "failure - unpack error", - data: []byte{1, 2, 3, 4}, - err: errors.New("unpack error: invalid data for unpacking"), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := setupEVMRegistry(t) - fl, err := r.decodeStreamsLookup(tt.data) - assert.Equal(t, tt.expected, fl) - if tt.err != nil { - assert.Equal(t, tt.err.Error(), err.Error()) - } - }) - } -} - func TestEvmRegistry_AllowedToUseMercury(t *testing.T) { upkeepId, ok := new(big.Int).SetString("71022726777042968814359024671382968091267501884371696415772139504780367423725", 10) assert.True(t, ok, t.Name()) @@ -414,7 +423,7 @@ func TestEvmRegistry_AllowedToUseMercury(t *testing.T) { } } -func TestEvmRegistry_DoMercuryRequest(t *testing.T) { +func TestEvmRegistry_DoMercuryRequestV02(t *testing.T) { upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) tests := []struct { @@ -431,12 +440,14 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { { name: "success", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(25880526), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, }, mockHttpStatusCode: http.StatusOK, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, @@ -447,12 +458,14 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { { name: "failure - retryable", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(25880526), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, }, mockHttpStatusCode: http.StatusInternalServerError, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, @@ -464,12 +477,14 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { { name: "failure - not retryable", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(25880526), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, }, mockHttpStatusCode: http.StatusBadGateway, mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, @@ -481,12 +496,14 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { { name: "failure - no feeds", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{}, - timeParamKey: blockNumber, - time: big.NewInt(25880526), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, }, expectedValues: [][]byte{}, reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, @@ -494,12 +511,14 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { { name: "failure - invalid revert data", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{}, - timeParamKey: blockNumber, - time: big.NewInt(25880526), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, }, expectedValues: [][]byte{}, reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, @@ -540,6 +559,81 @@ func TestEvmRegistry_DoMercuryRequest(t *testing.T) { } } +func TestEvmRegistry_DoMercuryRequestV03(t *testing.T) { + upkeepId, _ := new(big.Int).SetString("88786950015966611018675766524283132478093844178961698330929478019253453382042", 10) + + tests := []struct { + name string + lookup *StreamsLookup + mockHttpStatusCode int + mockChainlinkBlobs []string + expectedValues [][]byte + expectedRetryable bool + expectedError error + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason + }{ + { + name: "success v0.3", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(25880526), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, + }, + mockHttpStatusCode: http.StatusOK, + mockChainlinkBlobs: []string{"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}, + expectedValues: [][]byte{{0, 6, 109, 252, 209, 237, 45, 149, 177, 140, 148, 141, 188, 91, 214, 76, 104, 122, 254, 147, 228, 202, 125, 102, 61, 222, 193, 76, 32, 9, 10, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 69, 84, 72, 45, 85, 83, 68, 45, 65, 82, 66, 73, 84, 82, 85, 77, 45, 84, 69, 83, 84, 78, 69, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 216, 211, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 154, 207, 11, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 155, 61, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 206, 116, 217, 250, 37, 42, 137, 131, 151, 110, 171, 96, 13, 199, 89, 12, 119, 141, 4, 129, 52, 48, 132, 27, 198, 231, 101, 195, 76, 216, 26, 22, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 138, 231, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 137, 28, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 96, 65, 43, 148, 229, 37, 202, 108, 237, 201, 245, 68, 253, 134, 247, 118, 6, 213, 47, 231, 49, 165, 208, 105, 219, 232, 54, 168, 191, 192, 251, 140, 145, 25, 99, 176, 174, 122, 20, 151, 31, 59, 70, 33, 191, 251, 128, 46, 240, 96, 83, 146, 185, 166, 200, 156, 127, 171, 29, 248, 99, 58, 90, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 69, 0, 194, 245, 33, 248, 63, 186, 94, 252, 43, 243, 239, 250, 174, 221, 228, 61, 10, 74, 223, 247, 133, 193, 33, 59, 113, 42, 58, 237, 13, 129, 87, 100, 42, 132, 50, 77, 176, 207, 150, 149, 235, 210, 119, 8, 212, 96, 142, 176, 51, 126, 13, 216, 123, 14, 67, 240, 250, 112, 199, 0, 217, 17}}, + expectedRetryable: false, + expectedError: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := setupEVMRegistry(t) + hc := mocks.NewHttpClient(t) + + mr := MercuryV03Response{} + for i, blob := range tt.mockChainlinkBlobs { + r := MercuryV03Report{ + FeedID: tt.lookup.Feeds[i], + ValidFromTimestamp: 0, + ObservationsTimestamp: 0, + FullReport: blob, + } + mr.Reports = append(mr.Reports, r) + } + + b, err := json.Marshal(mr) + assert.Nil(t, err) + resp := &http.Response{ + StatusCode: tt.mockHttpStatusCode, + Body: io.NopCloser(bytes.NewReader(b)), + } + if tt.expectedError != nil && tt.expectedRetryable { + hc.On("Do", mock.Anything).Return(resp, nil).Times(totalAttempt) + } else { + hc.On("Do", mock.Anything).Return(resp, nil).Once() + } + r.hc = hc + + state, reason, values, retryable, reqErr := r.doMercuryRequest(context.Background(), tt.lookup, r.lggr) + assert.Equal(t, tt.expectedValues, values) + assert.Equal(t, tt.expectedRetryable, retryable) + assert.Equal(t, tt.state, state) + assert.Equal(t, tt.reason, reason) + if tt.expectedError != nil { + assert.Equal(t, tt.expectedError.Error(), reqErr.Error()) + } + }) + } +} + func TestEvmRegistry_SingleFeedRequest(t *testing.T) { upkeepId := big.NewInt(123456789) tests := []struct { @@ -557,11 +651,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "success - mercury responds in the first try", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dc00000012", }, @@ -569,11 +665,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "success - retry for 404", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dcbabbad", retryNumber: 1, @@ -584,11 +682,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "success - retry for 500", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dcbbabad", retryNumber: 2, @@ -599,11 +699,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "failure - returns retryable", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dc", retryNumber: totalAttempt, @@ -615,11 +717,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "failure - returns retryable and then non-retryable", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dc", retryNumber: 1, @@ -631,11 +735,13 @@ func TestEvmRegistry_SingleFeedRequest(t *testing.T) { name: "failure - returns not retryable", index: 0, lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, blob: "0xab2123dc", statusCode: http.StatusBadGateway, @@ -722,25 +828,56 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "success - mercury responds in the first try", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123456, ObservationsTimestamp: 123456, - FullReport: hexutil.MustDecode("0xab2123dc00000012"), + FullReport: "0xab2123dc00000012", }, { - FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123458, ObservationsTimestamp: 123458, - FullReport: hexutil.MustDecode("0xab2123dc00000016"), + FullReport: "0xab2123dc00000016", + }, + }, + }, + statusCode: http.StatusOK, + }, + { + name: "success - mercury responds in the first try with blocknumber", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000016", }, }, }, @@ -749,11 +886,13 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "success - retry for 500", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, retryNumber: 2, statusCode: http.StatusInternalServerError, @@ -761,28 +900,61 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123456, + ObservationsTimestamp: 123456, + FullReport: "0xab2123dc00000012", + }, + { + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", + ValidFromTimestamp: 123458, + ObservationsTimestamp: 123458, + FullReport: "0xab2123dc00000019", + }, + }, + }, + }, + { + name: "failure - fail to decode reportBlob", + lookup: &StreamsLookup{ + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, + }, + response: &MercuryV03Response{ + Reports: []MercuryV03Report{ + { + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123456, ObservationsTimestamp: 123456, - FullReport: hexutil.MustDecode("0xab2123dc00000012"), + FullReport: "qerwiu", // invalid hex blob }, { - FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123458, ObservationsTimestamp: 123458, - FullReport: hexutil.MustDecode("0xab2123dc00000019"), + FullReport: "0xab2123dc00000016", }, }, }, + statusCode: http.StatusOK, + retryable: false, + errorMessage: "All attempts fail:\n#1: hex string without 0x prefix", }, { name: "failure - returns retryable", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, retryNumber: totalAttempt, statusCode: http.StatusInternalServerError, @@ -792,11 +964,13 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "failure - returns retryable and then non-retryable", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, retryNumber: 1, statusCode: http.StatusInternalServerError, @@ -806,11 +980,13 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "failure - returns status code 420 not retryable", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, statusCode: 420, errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 420 from mercury v0.3, most likely this is caused by missing/malformed query args, missing or bad required headers, non-existent feeds, or no permissions for feeds", @@ -818,11 +994,13 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "failure - returns status code 502 not retryable", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, statusCode: http.StatusBadGateway, errorMessage: "All attempts fail:\n#1: at timestamp 123456 upkeep 123456789 received status code 502 from mercury v0.3", @@ -830,35 +1008,37 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { { name: "success - retry when reports length does not match feeds length", lookup: &StreamsLookup{ - feedParamKey: feedIDs, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: timestamp, - time: big.NewInt(123456), - upkeepId: upkeepId, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIDs, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: timestamp, + Time: big.NewInt(123456), + }, + upkeepId: upkeepId, }, firstResponse: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123456, ObservationsTimestamp: 123456, - FullReport: hexutil.MustDecode("0xab2123dc00000012"), + FullReport: "0xab2123dc00000012", }, }, }, response: &MercuryV03Response{ Reports: []MercuryV03Report{ { - FeedID: hexutil.MustDecode("0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123456, ObservationsTimestamp: 123456, - FullReport: hexutil.MustDecode("0xab2123dc00000012"), + FullReport: "0xab2123dc00000012", }, { - FeedID: hexutil.MustDecode("0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"), + FeedID: "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000", ValidFromTimestamp: 123458, ObservationsTimestamp: 123458, - FullReport: hexutil.MustDecode("0xab2123dc00000019"), + FullReport: "0xab2123dc00000019", }, }, }, @@ -930,7 +1110,8 @@ func TestEvmRegistry_MultiFeedRequest(t *testing.T) { assert.Nil(t, m.Error) var reports [][]byte for _, rsp := range tt.response.Reports { - reports = append(reports, rsp.FullReport) + b, _ := hexutil.Decode(rsp.FullReport) + reports = append(reports, b) } assert.Equal(t, reports, m.Bytes) } @@ -962,13 +1143,15 @@ func TestEvmRegistry_CheckCallback(t *testing.T) { { name: "success - empty extra data", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"ETD-USD", "BTC-ETH"}, - timeParamKey: blockNumber, - time: big.NewInt(100), - extraData: []byte{48, 120, 48, 48}, - upkeepId: upkeepId, - block: bn, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: blockNumber, + Time: big.NewInt(100), + ExtraData: []byte{48, 120, 48, 48}, + }, + upkeepId: upkeepId, + block: bn, }, values: values, statusCode: http.StatusOK, @@ -980,14 +1163,16 @@ func TestEvmRegistry_CheckCallback(t *testing.T) { { name: "success - with extra data", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - timeParamKey: blockNumber, - time: big.NewInt(18952430), - // this is the address of precompile contract ArbSys(0x0000000000000000000000000000000000000064) - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - upkeepId: upkeepId, - block: bn, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: blockNumber, + Time: big.NewInt(18952430), + // this is the address of precompile contract ArbSys(0x0000000000000000000000000000000000000064) + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + upkeepId: upkeepId, + block: bn, }, values: values, statusCode: http.StatusOK, @@ -999,13 +1184,15 @@ func TestEvmRegistry_CheckCallback(t *testing.T) { { name: "failure - bad response", lookup: &StreamsLookup{ - feedParamKey: feedIdHex, - feeds: []string{"ETD-USD", "BTC-ETH"}, - timeParamKey: blockNumber, - time: big.NewInt(100), - extraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - upkeepId: upkeepId, - block: bn, + StreamsLookupError: &encoding.StreamsLookupError{ + FeedParamKey: feedIdHex, + Feeds: []string{"ETD-USD", "BTC-ETH"}, + TimeParamKey: blockNumber, + Time: big.NewInt(100), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 48, 120, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + upkeepId: upkeepId, + block: bn, }, values: values, statusCode: http.StatusOK, @@ -1021,7 +1208,7 @@ func TestEvmRegistry_CheckCallback(t *testing.T) { t.Run(tt.name, func(t *testing.T) { client := new(evmClientMocks.Client) r := setupEVMRegistry(t) - payload, err := r.abi.Pack("checkCallback", tt.lookup.upkeepId, values, tt.lookup.extraData) + payload, err := r.abi.Pack("checkCallback", tt.lookup.upkeepId, values, tt.lookup.ExtraData) require.Nil(t, err) args := map[string]interface{}{ "to": r.addr.Hex(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go index 9ce9a10ac73..d70611313af 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/scanner.go @@ -79,7 +79,7 @@ func (s *performedEventsScanner) ScanWorkIDs(ctx context.Context, workID ...stri end = len(ids) } batch := ids[i:end] - batchLogs, err := s.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), s.registryAddress, 1, batch, int(s.finalityDepth), pg.WithParentCtx(ctx)) + batchLogs, err := s.poller.IndexedLogs(iregistry21.IKeeperRegistryMasterDedupKeyAdded{}.Topic(), s.registryAddress, 1, batch, logpoller.Confirmations(s.finalityDepth), pg.WithParentCtx(ctx)) if err != nil { return nil, fmt.Errorf("error fetching logs: %w", err) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go index 49851b584e8..8e2e77f7fb4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/upkeepstate/store_test.go @@ -8,11 +8,12 @@ import ( "testing" "time" - ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -561,11 +562,11 @@ func (_m *mockORM) setErr(err error) { _m.err = err } -func (_m *mockORM) BatchInsertRecords(state []persistedStateRecord, _ ...pg.QOpt) error { +func (_m *mockORM) BatchInsertRecords(state []persistedStateRecord, opts ...pg.QOpt) error { return nil } -func (_m *mockORM) SelectStatesByWorkIDs(workIDs []string, _ ...pg.QOpt) ([]persistedStateRecord, error) { +func (_m *mockORM) SelectStatesByWorkIDs(workIDs []string, opts ...pg.QOpt) ([]persistedStateRecord, error) { _m.lock.Lock() defer _m.lock.Unlock() @@ -575,7 +576,7 @@ func (_m *mockORM) SelectStatesByWorkIDs(workIDs []string, _ ...pg.QOpt) ([]pers return res, _m.err } -func (_m *mockORM) DeleteExpired(tm time.Time, _ ...pg.QOpt) error { +func (_m *mockORM) DeleteExpired(tm time.Time, opts ...pg.QOpt) error { _m.lock.Lock() defer _m.lock.Unlock() diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index e864b0d7e2f..15280de73cf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -20,15 +20,17 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/umbracle/ethgo/abi" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -476,7 +478,7 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK mServer.Start() // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, mServer) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -486,8 +488,9 @@ func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IK nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, mServer) diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index eea9c1574cf..7c881a18eb9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -21,8 +21,10 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -50,8 +52,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" @@ -108,15 +110,14 @@ func deployKeeper20Registry( func setupNode( t *testing.T, - port int64, + port int, dbName string, nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, mercury MercuryEndpoint, ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) + p2pKey := keystest.NewP2PKeyV2(t) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} cfg, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) @@ -238,7 +239,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { registry := deployKeeper20Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -248,8 +249,9 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) @@ -498,7 +500,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes - bootstrapNodePort := int64(19599) + bootstrapNodePort := freeport.GetOne(t) appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, "bootstrap_keeper_ocr", nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) bootstrapNode := Node{ @@ -509,8 +511,9 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { nodes []Node ) // Set up the minimum 4 oracles all funded - for i := int64(0); i < 4; i++ { - app, peerID, transmitter, kb := setupNode(t, bootstrapNodePort+i+1, fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + app, peerID, transmitter, kb := setupNode(t, ports[i], fmt.Sprintf("oracle_keeper%d", i), nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, }, NewSimulatedMercuryServer()) diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index b1d369168fe..e51b68f415d 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -911,7 +911,7 @@ func (c *coordinator) DKGVRFCommittees(ctx context.Context) (dkgCommittee, vrfCo latestVRF, err := c.lp.LatestLogByEventSigWithConfs( c.configSetTopic, c.beaconAddress, - int(c.finalityDepth), + logpoller.Confirmations(c.finalityDepth), pg.WithParentCtx(ctx), ) if err != nil { @@ -922,7 +922,7 @@ func (c *coordinator) DKGVRFCommittees(ctx context.Context) (dkgCommittee, vrfCo latestDKG, err := c.lp.LatestLogByEventSigWithConfs( c.configSetTopic, c.dkgAddress, - int(c.finalityDepth), + logpoller.Confirmations(c.finalityDepth), pg.WithParentCtx(ctx), ) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 1222ab7b2a4..26d0f2996a9 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -26,6 +26,7 @@ import ( ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lp_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -83,11 +84,11 @@ func TestCoordinator_DKGVRFCommittees(t *testing.T) { coordinatorAddress := newAddress(t) beaconAddress := newAddress(t) dkgAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, 10, mock.Anything). + lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, logpoller.Confirmations(10), mock.Anything). Return(&logpoller.Log{ Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), }, nil) - lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, dkgAddress, 10, mock.Anything). + lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, dkgAddress, logpoller.Confirmations(10), mock.Anything). Return(&logpoller.Log{ Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), }, nil) @@ -132,7 +133,7 @@ func TestCoordinator_DKGVRFCommittees(t *testing.T) { tp := newTopics() beaconAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, 10, mock.Anything). + lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, logpoller.Confirmations(10), mock.Anything). Return(nil, errors.New("rpc error")) c := &coordinator{ @@ -154,11 +155,11 @@ func TestCoordinator_DKGVRFCommittees(t *testing.T) { beaconAddress := newAddress(t) coordinatorAddress := newAddress(t) dkgAddress := newAddress(t) - lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, 10, mock.Anything). + lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, beaconAddress, logpoller.Confirmations(10), mock.Anything). Return(&logpoller.Log{ Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000a6fca200010576e704b4a519484d6239ef17f1f5b4a82e330b0daf827ed4dc2789971b0000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000a8cbea12a06869d3ec432ab9682dab6c761d591000000000000000000000000f4f9db7bb1d16b7cdfb18ec68994c26964f5985300000000000000000000000022fb3f90c539457f00d8484438869135e604a65500000000000000000000000033cbcedccb11c9773ad78e214ba342e979255ab30000000000000000000000006ffaa96256fbc1012325cca88c79f725c33eed80000000000000000000000000000000000000000000000000000000000000000500000000000000000000000074103cf8b436465870b26aa9fa2f62ad62b22e3500000000000000000000000038a6cb196f805cc3041f6645a5a6cec27b64430d00000000000000000000000047d7095cfebf8285bdaa421bc8268d0db87d933c000000000000000000000000a8842be973800ff61d80d2d53fa62c3a685380eb0000000000000000000000003750e31321aee8c024751877070e8d5f704ce98700000000000000000000000000000000000000000000000000000000000000206f3b82406688b8ddb944c6f2e6d808f014c8fa8d568d639c25019568c715fbf000000000000000000000000000000000000000000000000000000000000004220880d88ee16f1080c8afa0251880c8afa025208090dfc04a288090dfc04a30033a05010101010142206c5ca6f74b532222ac927dd3de235d46a943e372c0563393a33b01dcfd3f371c4220855114d25c2ef5e85fffe4f20a365672d8f2dba3b2ec82333f494168a2039c0442200266e835634db00977cbc1caa4db10e1676c1a4c0fcbc6ba7f09300f0d1831824220980cd91f7a73f20f4b0d51d00cd4e00373dc2beafbb299ca3c609757ab98c8304220eb6d36e2af8922085ff510bbe1eb8932a0e3295ca9f047fef25d90e69c52948f4a34313244334b6f6f574463364b7232644542684b59326b336e685057694676544565325331703978544532544b74344d7572716f684a34313244334b6f6f574b436e4367724b637743324a3577576a626e355435335068646b6b6f57454e534a39546537544b7836366f4a4a34313244334b6f6f575239616f675948786b357a38636b624c4c56346e426f7a777a747871664a7050586671336d4a7232796452474a34313244334b6f6f5744695444635565675637776b313133473366476a69616259756f54436f3157726f6f53656741343263556f544a34313244334b6f6f574e64687072586b5472665370354d5071736270467a70364167394a53787358694341434442676454424c656652820300050e416c74424e2d3132382047e282810e86e8cf899ae9a1b43e023bbe8825b103659bb8d6d4e54f6a3cfae7b106069c216a812d7616e47f0bd38fa4863f48fbcda6a38af4c58d2233dfa7cf79620947042d09f923e0a2f7a2270391e8b058d8bdb8f79fe082b7b627f025651c7290382fdff97c3181d15d162c146ce87ff752499d2acc2b26011439a12e29571a6f1e1defb1751c3be4258c493984fd9f0f6b4a26c539870b5f15bfed3d8ffac92499eb62dbd2beb7c1524275a8019022f6ce6a7e86c9e65e3099452a2b96fc2432b127a112970e1adf615f823b2b2180754c2f0ee01f1b389e56df55ca09702cd0401b66ff71779d2dd67222503a85ab921b28c329cc1832800b192d0b0247c0776e1b9653dc00df48daa6364287c84c0382f5165e7269fef06d10bc67c1bba252305d1af0dc7bb0fe92558eb4c5f38c23163dee1cfb34a72020669dbdfe337c16f3307472616e736c61746f722066726f6d20416c74424e2d3132382047e2828120746f20416c74424e2d3132382047e282825880ade2046080c8afa0256880c8afa0257080ade204788094ebdc0382019e010a205034214e0bd4373f38e162cf9fc9133e2f3b71441faa4c3d1ac01c1877f1cd2712200e03e975b996f911abba2b79d2596c2150bc94510963c40a1137a03df6edacdb1a107dee1cdb894163813bb3da604c9c133c1a10bb33302eeafbd55d352e35dcc5d2b3311a10d2c658b6b93d74a02d467849b6fe75251a10fea5308cc1fea69e7246eafe7ca8a3a51a1048efe1ad873b6f025ac0243bdef715f8000000000000000000000000000000000000000000000000000000000000"), }, nil) - lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, dkgAddress, 10, mock.Anything). + lp.On("LatestLogByEventSigWithConfs", tp.configSetTopic, dkgAddress, logpoller.Confirmations(10), mock.Anything). Return(nil, errors.New("rpc error")) c := &coordinator{ @@ -1218,7 +1219,7 @@ func TestCoordinator_ReportIsOnchain(t *testing.T) { log.BlockNumber = 195 lp.On("IndexedLogs", tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ enrTopic, - }, 1, mock.Anything).Return([]logpoller.Log{log}, nil) + }, logpoller.Confirmations(1), mock.Anything).Return([]logpoller.Log{log}, nil) c := &coordinator{ lp: lp, @@ -1254,7 +1255,7 @@ func TestCoordinator_ReportIsOnchain(t *testing.T) { log.BlockNumber = 195 lp.On("IndexedLogs", tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ enrTopic, - }, 1, mock.Anything).Return([]logpoller.Log{log}, nil) + }, logpoller.Confirmations(1), mock.Anything).Return([]logpoller.Log{log}, nil) c := &coordinator{ lp: lp, @@ -1281,7 +1282,7 @@ func TestCoordinator_ReportIsOnchain(t *testing.T) { lp := lp_mocks.NewLogPoller(t) lp.On("IndexedLogs", tp.newTransmissionTopic, beaconAddress, 2, []common.Hash{ enrTopic, - }, 1, mock.Anything).Return([]logpoller.Log{}, nil) + }, logpoller.Confirmations(1), mock.Anything).Return([]logpoller.Log{}, nil) c := &coordinator{ lp: lp, diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go index b13df9a71aa..d3fe5c91195 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -1876,13 +1876,12 @@ func (_m *VRFBeaconInterface) WithdrawPayment(opts *bind.TransactOpts, transmitt return r0, r1 } -type mockConstructorTestingTNewVRFBeaconInterface interface { +// NewVRFBeaconInterface creates a new instance of VRFBeaconInterface. 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 NewVRFBeaconInterface(t interface { mock.TestingT Cleanup(func()) -} - -// NewVRFBeaconInterface creates a new instance of VRFBeaconInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewVRFBeaconInterface(t mockConstructorTestingTNewVRFBeaconInterface) *VRFBeaconInterface { +}) *VRFBeaconInterface { mock := &VRFBeaconInterface{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go index cf09042ca3a..835702d136a 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_beacon_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -149,13 +149,12 @@ func (_m *VRFBeaconCoordinator) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, return r0, r1 } -type mockConstructorTestingTNewVRFBeaconCoordinator interface { +// NewVRFBeaconCoordinator creates a new instance of VRFBeaconCoordinator. 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 NewVRFBeaconCoordinator(t interface { mock.TestingT Cleanup(func()) -} - -// NewVRFBeaconCoordinator creates a new instance of VRFBeaconCoordinator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewVRFBeaconCoordinator(t mockConstructorTestingTNewVRFBeaconCoordinator) *VRFBeaconCoordinator { +}) *VRFBeaconCoordinator { mock := &VRFBeaconCoordinator{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go index a4dc64583ed..d5e373f4bca 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks/vrf_coordinator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -2666,13 +2666,12 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferred(opts *bind. return r0, r1 } -type mockConstructorTestingTNewVRFCoordinatorInterface interface { +// NewVRFCoordinatorInterface creates a new instance of VRFCoordinatorInterface. 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 NewVRFCoordinatorInterface(t interface { mock.TestingT Cleanup(func()) -} - -// NewVRFCoordinatorInterface creates a new instance of VRFCoordinatorInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewVRFCoordinatorInterface(t mockConstructorTestingTNewVRFCoordinatorInterface) *VRFCoordinatorInterface { +}) *VRFCoordinatorInterface { mock := &VRFCoordinatorInterface{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go index 66b14c00f5b..77384a085ab 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/router.go @@ -71,9 +71,8 @@ func (v *vrfRouter) ParseLog(log types.Log) (generated.AbigenLog, error) { return v.beacon.ParseLog(log) } else if log.Address == v.coordinator.Address() { return v.coordinator.ParseLog(log) - } else { - return nil, errors.Errorf("failed to parse log. contractAddress: %x logs: %x", log.Address, log.Topics) } + return nil, errors.Errorf("failed to parse log. contractAddress: %x logs: %x", log.Address, log.Topics) } // GetConfirmationDelays retrieves confirmation delays from the on-chain contract. diff --git a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go index c6a4552683a..b9a4d500026 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "math/big" - "net" "testing" "time" @@ -19,7 +18,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/hashicorp/consul/sdk/freeport" "github.com/onsi/gomega" + "github.com/stretchr/testify/require" + "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/libocr/commontypes" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -27,9 +30,6 @@ import ( ocr2dkg "github.com/smartcontractkit/ocr2vrf/dkg" "github.com/smartcontractkit/ocr2vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/ocr2vrf/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.dedis.ch/kyber/v3" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -48,8 +48,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -218,14 +219,13 @@ func setupOCR2VRFContracts( func setupNodeOCR2( t *testing.T, owner *bind.TransactOpts, - port uint16, + port int, dbName string, b *backends.SimulatedBackend, useForwarders bool, p2pV2Bootstrappers []commontypes.BootstrapperLocator, ) *ocr2Node { - p2pKey, err := p2pkey.NewV2() - require.NoError(t, err) + p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, fmt.Sprintf("%s%d", dbName, port), func(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test. @@ -252,9 +252,13 @@ func setupNodeOCR2( app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) - require.NoError(t, err) - require.Len(t, sendingKeys, 1) + var sendingKeys []ethkey.KeyV2 + { + var err error + sendingKeys, err = app.KeyStore.Eth().EnabledKeysForChain(testutils.SimulatedChainID) + require.NoError(t, err) + require.Len(t, sendingKeys, 1) + } transmitter := sendingKeys[0].Address effectiveTransmitter := sendingKeys[0].Address @@ -337,7 +341,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { t.Log("Creating bootstrap node") - bootstrapNodePort := getFreePort(t) + bootstrapNodePort := freeport.GetOne(t) bootstrapNode := setupNodeOCR2(t, uni.owner, bootstrapNodePort, "bootstrap", uni.backend, false, nil) numNodes := 5 @@ -355,6 +359,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { dkgSigners []dkgsignkey.Key sendingKeys [][]string ) + ports := freeport.GetN(t, numNodes) for i := 0; i < numNodes; i++ { // Supply the bootstrap IP and port as a V2 peer address bootstrappers := []commontypes.BootstrapperLocator{ @@ -362,7 +367,7 @@ func runOCR2VRFTest(t *testing.T, useForwarders bool) { fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort), }}, } - node := setupNodeOCR2(t, uni.owner, getFreePort(t), fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) + node := setupNodeOCR2(t, uni.owner, ports[i], fmt.Sprintf("ocr2vrforacle%d", i), uni.backend, useForwarders, bootstrappers) sendingKeys = append(sendingKeys, node.sendingKeys) dkgSignKey, err := node.app.GetKeyStore().DKGSign().Create() @@ -492,10 +497,10 @@ linkEthFeedAddress = "%s" uni.feedAddress.String(), ) t.Log("Creating OCR2VRF job with spec:", jobSpec) - ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec) - require.NoError(t, err) - err = apps[i].AddJobV2(context.Background(), &ocrJob) - require.NoError(t, err) + ocrJob2, err2 := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), jobSpec) + require.NoError(t, err2) + err2 = apps[i].AddJobV2(context.Background(), &ocrJob2) + require.NoError(t, err2) } t.Log("Waiting for DKG key to get written") @@ -504,10 +509,10 @@ linkEthFeedAddress = "%s" var emptyKH [32]byte emptyHash := crypto.Keccak256Hash(emptyKH[:]) gomega.NewWithT(t).Eventually(func() bool { - kh, err := uni.beacon.SProvingKeyHash(&bind.CallOpts{ + kh, err2 := uni.beacon.SProvingKeyHash(&bind.CallOpts{ Context: testutils.Context(t), }) - require.NoError(t, err) + require.NoError(t, err2) t.Log("proving keyhash:", hexutil.Encode(kh[:])) return crypto.Keccak256Hash(kh[:]) != emptyHash }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) @@ -590,9 +595,9 @@ linkEthFeedAddress = "%s" // poll until we're able to redeem the randomness without reverting // at that point, it's been fulfilled gomega.NewWithT(t).Eventually(func() bool { - _, err := uni.consumer.TestRedeemRandomness(uni.owner, uni.subID, redemptionRequestID) - t.Logf("TestRedeemRandomness err: %+v", err) - return err == nil + _, err2 := uni.consumer.TestRedeemRandomness(uni.owner, uni.subID, redemptionRequestID) + t.Logf("TestRedeemRandomness err: %+v", err2) + return err2 == nil }, testutils.WaitTimeout(t), 5*time.Second).Should(gomega.BeTrue()) gomega.NewWithT(t).Eventually(func() bool { @@ -600,8 +605,8 @@ linkEthFeedAddress = "%s" // We use an upper and lower bound such that this part of the test is not excessively brittle to upstream tweaks. refundUpperBound := big.NewInt(0).Add(assets.GWei(17_000_000).ToInt(), subAfterBatchFulfillmentRequest.Balance) refundLowerBound := big.NewInt(0).Add(assets.GWei(15_000_000).ToInt(), subAfterBatchFulfillmentRequest.Balance) - subAfterRefund, err := uni.coordinator.GetSubscription(nil, uni.subID) - require.NoError(t, err) + subAfterRefund, err2 := uni.coordinator.GetSubscription(nil, uni.subID) + require.NoError(t, err2) balanceAfterRefund = subAfterRefund.Balance if ok := ((balanceAfterRefund.Cmp(refundUpperBound) == -1) && (balanceAfterRefund.Cmp(refundLowerBound) == 1)); !ok { t.Logf("unexpected sub balance after refund: %d", balanceAfterRefund) @@ -625,8 +630,8 @@ linkEthFeedAddress = "%s" // get total owed amount to NOPs and ensure linkAvailableForPayment (CLL profit) calculation is correct nopOwedAmount := new(big.Int) for _, transmitter := range transmitters { - owedAmount, err := uni.beacon.OwedPayment(nil, transmitter) - require.NoError(t, err) + owedAmount, err2 := uni.beacon.OwedPayment(nil, transmitter) + require.NoError(t, err2) nopOwedAmount = new(big.Int).Add(nopOwedAmount, owedAmount) } linkAvailable, err := uni.beacon.LinkAvailableForPayment(nil) @@ -655,27 +660,27 @@ linkEthFeedAddress = "%s" totalNopPayout := new(big.Int) for idx, payeeTransactor := range payeeTransactors { // Fund the payee with some ETH. - n, err := uni.backend.NonceAt(testutils.Context(t), uni.owner.From, nil) - require.NoError(t, err) + n, err2 := uni.backend.NonceAt(testutils.Context(t), uni.owner.From, nil) + require.NoError(t, err2) tx := types.NewTransaction( n, payeeTransactor.From, assets.Ether(1).ToInt(), 21000, assets.GWei(1).ToInt(), nil) - signedTx, err := uni.owner.Signer(uni.owner.From, tx) - require.NoError(t, err) - err = uni.backend.SendTransaction(testutils.Context(t), signedTx) - require.NoError(t, err) + signedTx, err2 := uni.owner.Signer(uni.owner.From, tx) + require.NoError(t, err2) + err2 = uni.backend.SendTransaction(testutils.Context(t), signedTx) + require.NoError(t, err2) - _, err = uni.beacon.WithdrawPayment(payeeTransactor, transmitters[idx]) - require.NoError(t, err) + _, err2 = uni.beacon.WithdrawPayment(payeeTransactor, transmitters[idx]) + require.NoError(t, err2) uni.backend.Commit() - payoutAmount, err := uni.link.BalanceOf(nil, payeeTransactor.From) - require.NoError(t, err) + payoutAmount, err2 := uni.link.BalanceOf(nil, payeeTransactor.From) + require.NoError(t, err2) totalNopPayout = new(big.Int).Add(totalNopPayout, payoutAmount) - owedAmountAfter, err := uni.beacon.OwedPayment(nil, transmitters[idx]) - require.NoError(t, err) + owedAmountAfter, err2 := uni.beacon.OwedPayment(nil, transmitters[idx]) + require.NoError(t, err2) require.True(t, owedAmountAfter.Cmp(big.NewInt(0)) == 0) } require.True(t, nopOwedAmount.Cmp(totalNopPayout) == 0) @@ -709,33 +714,33 @@ linkEthFeedAddress = "%s" gomega.NewWithT(t).Eventually(func() bool { var errs []error - rw1, err := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(0)) - t.Logf("TestRedeemRandomness 1st word err: %+v", err) - errs = append(errs, err) - rw2, err := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(1)) - t.Logf("TestRedeemRandomness 2nd word err: %+v", err) - errs = append(errs, err) - rw3, err := uni.consumer.SReceivedRandomnessByRequestID(nil, fulfillmentRequestID, big.NewInt(0)) - t.Logf("FulfillRandomness 1st word err: %+v", err) - errs = append(errs, err) - rw4, err := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID1, big.NewInt(0)) - t.Logf("Batch FulfillRandomness 1st word err: %+v", err) - errs = append(errs, err) - rw5, err := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID2, big.NewInt(0)) - t.Logf("Batch FulfillRandomness 2nd word err: %+v", err) - errs = append(errs, err) - batchTotalRequests, err := uni.loadTestConsumer.STotalRequests(nil) - t.Logf("Batch FulfillRandomness total requests err: %+v", err) - errs = append(errs, err) - batchTotalFulfillments, err := uni.loadTestConsumer.STotalFulfilled(nil) - t.Logf("Batch FulfillRandomness total fulfillments err: %+v", err) - errs = append(errs, err) - err = nil + rw1, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(0)) + t.Logf("TestRedeemRandomness 1st word err: %+v", err2) + errs = append(errs, err2) + rw2, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, redemptionRequestID, big.NewInt(1)) + t.Logf("TestRedeemRandomness 2nd word err: %+v", err2) + errs = append(errs, err2) + rw3, err2 := uni.consumer.SReceivedRandomnessByRequestID(nil, fulfillmentRequestID, big.NewInt(0)) + t.Logf("FulfillRandomness 1st word err: %+v", err2) + errs = append(errs, err2) + rw4, err2 := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID1, big.NewInt(0)) + t.Logf("Batch FulfillRandomness 1st word err: %+v", err2) + errs = append(errs, err2) + rw5, err2 := uni.loadTestConsumer.SReceivedRandomnessByRequestID(nil, batchFulfillmentRequestID2, big.NewInt(0)) + t.Logf("Batch FulfillRandomness 2nd word err: %+v", err2) + errs = append(errs, err2) + batchTotalRequests, err2 := uni.loadTestConsumer.STotalRequests(nil) + t.Logf("Batch FulfillRandomness total requests err: %+v", err2) + errs = append(errs, err2) + batchTotalFulfillments, err2 := uni.loadTestConsumer.STotalFulfilled(nil) + t.Logf("Batch FulfillRandomness total fulfillments err: %+v", err2) + errs = append(errs, err2) + err2 = nil if batchTotalRequests.Int64() != batchTotalFulfillments.Int64() { - err = errors.New("batchTotalRequests is not equal to batchTotalFulfillments") - errs = append(errs, err) + err2 = errors.New("batchTotalRequests is not equal to batchTotalFulfillments") + errs = append(errs, err2) } - t.Logf("Batch FulfillRandomness total requests/fulfillments equal err: %+v", err) + t.Logf("Batch FulfillRandomness total requests/fulfillments equal err: %+v", err2) t.Logf("randomness from redeemRandomness: %s %s", rw1.String(), rw2.String()) t.Logf("randomness from fulfillRandomness: %s", rw3.String()) @@ -875,15 +880,4 @@ func randomKeyID(t *testing.T) (r [32]byte) { return } -func getFreePort(t *testing.T) uint16 { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - require.NoError(t, err) - - l, err := net.ListenTCP("tcp", addr) - require.NoError(t, err) - defer func() { assert.NoError(t, l.Close()) }() - - return uint16(l.Addr().(*net.TCPAddr).Port) -} - func ptr[T any](v T) *T { return &v } diff --git a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go index a68c27e0e92..ba97eda30b1 100644 --- a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go +++ b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -59,13 +59,12 @@ func (_m *PrometheusBackend) SetShouldTransmitAcceptedReportDuration(_a0 []strin _m.Called(_a0, _a1) } -type mockConstructorTestingTNewPrometheusBackend interface { +// NewPrometheusBackend creates a new instance of PrometheusBackend. 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 NewPrometheusBackend(t interface { mock.TestingT Cleanup(func()) -} - -// NewPrometheusBackend creates a new instance of PrometheusBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewPrometheusBackend(t mockConstructorTestingTNewPrometheusBackend) *PrometheusBackend { +}) *PrometheusBackend { mock := &PrometheusBackend{} mock.Mock.Test(t) diff --git a/core/services/ocr2/plugins/s4/integration_test.go b/core/services/ocr2/plugins/s4/integration_test.go index 01b269e2c85..98ccd312e4b 100644 --- a/core/services/ocr2/plugins/s4/integration_test.go +++ b/core/services/ocr2/plugins/s4/integration_test.go @@ -4,6 +4,7 @@ import ( "context" "crypto/ecdsa" "fmt" + "maps" "math/rand" "testing" "time" @@ -26,7 +27,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/multierr" - "golang.org/x/exp/maps" ) // Disclaimer: this is not a true integration test, it's more of a S4 feature test, on purpose. diff --git a/core/services/ocr2/plugins/s4/plugin.go b/core/services/ocr2/plugins/s4/plugin.go index 7e4b91be97e..68bd9fd2142 100644 --- a/core/services/ocr2/plugins/s4/plugin.go +++ b/core/services/ocr2/plugins/s4/plugin.go @@ -253,6 +253,16 @@ func (c *plugin) ShouldAcceptFinalizedReport(ctx context.Context, ts types.Repor Confirmed: true, Signature: row.Signature, } + + now := time.Now().UnixMilli() + if now > ormRow.Expiration { + c.logger.Error("Received an expired entry in a report, not saving", commontypes.LogFields{ + "expirationTs": ormRow.Expiration, + "nowTs": now, + }) + continue + } + err = c.orm.Update(ormRow, pg.WithParentCtx(ctx)) if err != nil && !errors.Is(err, s4.ErrVersionTooLow) { c.logger.Error("Failed to Update a row in ShouldAcceptFinalizedReport()", commontypes.LogFields{"err": err}) diff --git a/core/services/ocr2/plugins/s4/plugin_test.go b/core/services/ocr2/plugins/s4/plugin_test.go index b85ba053122..94c876a4f7f 100644 --- a/core/services/ocr2/plugins/s4/plugin_test.go +++ b/core/services/ocr2/plugins/s4/plugin_test.go @@ -235,6 +235,21 @@ func TestPlugin_ShouldAcceptFinalizedReport(t *testing.T) { assert.NoError(t, err) // errors just logged assert.False(t, should) }) + + t.Run("don't save expired", func(t *testing.T) { + ormRows := make([]*s4_svc.Row, 0) + rows := generateTestRows(t, 2, -time.Minute) + + report, err := proto.Marshal(&s4.Rows{ + Rows: rows, + }) + assert.NoError(t, err) + + should, err := plugin.ShouldAcceptFinalizedReport(testutils.Context(t), types.ReportTimestamp{}, report) + assert.NoError(t, err) + assert.False(t, should) + assert.Equal(t, 0, len(ormRows)) + }) } func TestPlugin_Query(t *testing.T) { diff --git a/core/services/ocr2/plugins/threshold/decryption_queue_test.go b/core/services/ocr2/plugins/threshold/decryption_queue_test.go index bf7deb6bbbe..2a9f8d4c85b 100644 --- a/core/services/ocr2/plugins/threshold/decryption_queue_test.go +++ b/core/services/ocr2/plugins/threshold/decryption_queue_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - . "github.com/onsi/gomega" + "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -445,28 +445,28 @@ func Test_decryptionQueue_Close(t *testing.T) { } func waitForPendingRequestToBeAdded(t *testing.T, dq *decryptionQueue, ciphertextId decryptionPlugin.CiphertextId) { - NewGomegaWithT(t).Eventually(func() bool { + gomega.NewGomegaWithT(t).Eventually(func() bool { dq.mu.RLock() _, exists := dq.pendingRequests[string(ciphertextId)] dq.mu.RUnlock() return exists - }, testutils.WaitTimeout(t), "10ms").Should(BeTrue(), "pending request should be added") + }, testutils.WaitTimeout(t), "10ms").Should(gomega.BeTrue(), "pending request should be added") } func waitForPendingRequestToBeRemoved(t *testing.T, dq *decryptionQueue, ciphertextId decryptionPlugin.CiphertextId) { - NewGomegaWithT(t).Eventually(func() bool { + gomega.NewGomegaWithT(t).Eventually(func() bool { dq.mu.RLock() _, exists := dq.pendingRequests[string(ciphertextId)] dq.mu.RUnlock() return exists - }, testutils.WaitTimeout(t), "10ms").Should(BeFalse(), "pending request should be removed") + }, testutils.WaitTimeout(t), "10ms").Should(gomega.BeFalse(), "pending request should be removed") } func waitForCompletedRequestToBeAdded(t *testing.T, dq *decryptionQueue, ciphertextId decryptionPlugin.CiphertextId) { - NewGomegaWithT(t).Eventually(func() bool { + gomega.NewGomegaWithT(t).Eventually(func() bool { dq.mu.RLock() _, exists := dq.completedRequests[string(ciphertextId)] dq.mu.RUnlock() return exists - }, testutils.WaitTimeout(t), "10ms").Should(BeFalse(), "completed request should be removed") + }, testutils.WaitTimeout(t), "10ms").Should(gomega.BeFalse(), "completed request should be removed") } diff --git a/core/services/ocr2/plugins/threshold/mocks/decryptor.go b/core/services/ocr2/plugins/threshold/mocks/decryptor.go index 7b899262904..4b91cbbd26f 100644 --- a/core/services/ocr2/plugins/threshold/mocks/decryptor.go +++ b/core/services/ocr2/plugins/threshold/mocks/decryptor.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -40,13 +40,12 @@ func (_m *Decryptor) Decrypt(ctx context.Context, ciphertextId decryptionplugin. return r0, r1 } -type mockConstructorTestingTNewDecryptor interface { +// NewDecryptor creates a new instance of Decryptor. 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 NewDecryptor(t interface { mock.TestingT Cleanup(func()) -} - -// NewDecryptor creates a new instance of Decryptor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewDecryptor(t mockConstructorTestingTNewDecryptor) *Decryptor { +}) *Decryptor { mock := &Decryptor{} mock.Mock.Test(t) diff --git a/core/services/ocr2/validate/config.go b/core/services/ocr2/validate/config.go index 11f225e968a..549b929b23c 100644 --- a/core/services/ocr2/validate/config.go +++ b/core/services/ocr2/validate/config.go @@ -65,20 +65,16 @@ func ToLocalConfig(ocr2Config OCR2Config, insConf InsecureConfig, spec job.OCR2O return lc, nil } -var ( - minOCR2MaxDurationQuery = 100 * time.Millisecond - minOCR2MaxDurationQueryErr error - minOCR2MaxDurationQueryOnce sync.Once -) +const defaultMinOCR2MaxDurationQuery = 100 * time.Millisecond -func getMinOCR2MaxDurationQuery() (time.Duration, error) { - minOCR2MaxDurationQueryOnce.Do(func() { - if v := env.MinOCR2MaxDurationQuery.Get(); v != "" { - minOCR2MaxDurationQuery, minOCR2MaxDurationQueryErr = time.ParseDuration(v) - if minOCR2MaxDurationQueryErr != nil { - minOCR2MaxDurationQueryErr = fmt.Errorf("failed to parse %s: %w", env.MinOCR2MaxDurationQuery, minOCR2MaxDurationQueryErr) - } - } - }) - return minOCR2MaxDurationQuery, minOCR2MaxDurationQueryErr -} +var getMinOCR2MaxDurationQuery = sync.OnceValues(func() (time.Duration, error) { + str := env.MinOCR2MaxDurationQuery.Get() + if str == "" { + return defaultMinOCR2MaxDurationQuery, nil + } + d, err := time.ParseDuration(str) + if err != nil { + return -1, fmt.Errorf("failed to parse %s: %w", env.MinOCR2MaxDurationQuery, err) + } + return d, nil +}) diff --git a/core/services/ocrbootstrap/delegate.go b/core/services/ocrbootstrap/delegate.go index 9f9efca68e2..3910ca05d38 100644 --- a/core/services/ocrbootstrap/delegate.go +++ b/core/services/ocrbootstrap/delegate.go @@ -76,7 +76,7 @@ func (d *Delegate) BeforeJobCreated(spec job.Job) { } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) (services []job.ServiceCtx, err error) { +func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { spec := jb.BootstrapSpec if spec == nil { return nil, errors.Errorf("Bootstrap.Delegate expects an *job.BootstrapSpec to be present, got %v", jb) diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 18c8b82bfa6..45edc64e9db 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -25,8 +25,6 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM encrypted_key_rings`))) - peerID, err := p2ppeer.Decode("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") require.NoError(t, err) @@ -51,12 +49,11 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { c.P2P.V1.Enabled = ptr(true) c.P2P.PeerID = ptr(k.PeerID()) }) - keyStore = cltest.NewKeyStore(t, db, cfg.Database()) - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.NoError(t, pw.Start(testutils.Context(t)), "foo") require.Equal(t, k.PeerID(), pw.PeerID) + require.NoError(t, pw.Close()) }) t.Run("with one p2p key and mismatching P2P.PeerID returns error", func(t *testing.T) { @@ -66,6 +63,9 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + _, err := keyStore.P2P().Create() + require.NoError(t, err) + pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.Contains(t, pw.Start(testutils.Context(t)).Error(), "unable to find P2P key with id") @@ -83,12 +83,12 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { c.P2P.V1.Enabled = ptr(true) c.P2P.PeerID = ptr(k2.PeerID()) }) - keyStore = cltest.NewKeyStore(t, db, cfg.Database()) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.NoError(t, pw.Start(testutils.Context(t)), "foo") require.Equal(t, k2.PeerID(), pw.PeerID) + require.NoError(t, pw.Close()) }) t.Run("with multiple p2p keys and mismatching P2P.PeerID returns error", func(t *testing.T) { @@ -98,6 +98,9 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) + _, err := keyStore.P2P().Create() + require.NoError(t, err) + pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.Contains(t, pw.Start(testutils.Context(t)).Error(), "unable to find P2P key with id") @@ -109,8 +112,6 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { db := pgtest.NewSqlxDB(t) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM encrypted_key_rings`))) - cfg := configtest.NewGeneralConfig(t, nil) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) k, err := keyStore.P2P().Create() @@ -130,20 +131,19 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { c.P2P.V2.AnnounceAddresses = ptr(p2paddresses) }) - keyStore = cltest.NewKeyStore(t, db, cfg.Database()) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.NoError(t, pw.Start(testutils.Context(t))) require.True(t, pw.IsStarted(), "Should have started successfully") - pw.Close() + require.NoError(t, pw.Close()) /* If peer is still stuck in listenLoop, we will get a bind error trying to start on the same port */ require.False(t, pw.IsStarted()) pw = ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) require.NoError(t, pw.Start(testutils.Context(t)), "Should have shut down gracefully, and be able to re-use same port") require.True(t, pw.IsStarted(), "Should have started successfully") - pw.Close() + require.NoError(t, pw.Close()) } func TestSingletonPeerWrapper_PeerConfig(t *testing.T) { diff --git a/core/services/ocrcommon/peerstore_test.go b/core/services/ocrcommon/peerstore_test.go index 99d44229b19..ba55e0767ab 100644 --- a/core/services/ocrcommon/peerstore_test.go +++ b/core/services/ocrcommon/peerstore_test.go @@ -89,7 +89,7 @@ func Test_Peerstore_WriteToDB(t *testing.T) { err = wrapper.WriteToDB() require.NoError(t, err) - peers := make([]ocrcommon.P2PPeer, 0) + var peers []ocrcommon.P2PPeer err = db.Select(&peers, `SELECT * FROM p2p_peers`) require.NoError(t, err) require.Equal(t, 1, len(peers)) diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index 636a18262e1..54a5002093d 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -3,6 +3,7 @@ package ocrcommon import ( "context" "encoding/json" + "fmt" "github.com/ethereum/go-ethereum/common" @@ -353,7 +354,7 @@ func ShouldCollectEnhancedTelemetryMercury(job *job.Job) bool { // bid and ask. This functions expects the pipeline.TaskRunResults to be correctly ordered func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.TaskRunResult, allTasks *pipeline.TaskRunResults) (float64, float64, float64) { var benchmarkPrice, askPrice, bidPrice float64 - var ok bool + var err error //We rely on task results to be sorted in the correct order benchmarkPriceTask := allTasks.GetNextTaskOf(startTask) if benchmarkPriceTask == nil { @@ -361,33 +362,45 @@ func (e *EnhancedTelemetryService[T]) getPricesFromResults(startTask pipeline.Ta return 0, 0, 0 } if benchmarkPriceTask.Task.Type() == pipeline.TaskTypeJSONParse { - benchmarkPrice, ok = benchmarkPriceTask.Result.Value.(float64) - if !ok { - e.lggr.Warnf("cannot parse enhanced EA telemetry benchmark price, job %d, id %s", e.job.ID, benchmarkPriceTask.Task.DotID()) + if benchmarkPriceTask.Result.Error != nil { + e.lggr.Warnw(fmt.Sprintf("got error for enhanced EA telemetry benchmark price, job %d, id %s: %s", e.job.ID, benchmarkPriceTask.Task.DotID(), benchmarkPriceTask.Result.Error), "err", benchmarkPriceTask.Result.Error) + } else { + benchmarkPrice, err = getResultFloat64(benchmarkPriceTask) + if err != nil { + e.lggr.Warnw(fmt.Sprintf("cannot parse enhanced EA telemetry benchmark price, job %d, id %s", e.job.ID, benchmarkPriceTask.Task.DotID()), "err", err) + } } } bidTask := allTasks.GetNextTaskOf(*benchmarkPriceTask) if bidTask == nil { e.lggr.Warnf("cannot parse enhanced EA telemetry bid price, task is nil, job %d, id %s", e.job.ID) - return 0, 0, 0 + return benchmarkPrice, 0, 0 } if bidTask.Task.Type() == pipeline.TaskTypeJSONParse { - bidPrice, ok = bidTask.Result.Value.(float64) - if !ok { - e.lggr.Warnf("cannot parse enhanced EA telemetry bid price, job %d, id %s", e.job.ID, bidTask.Task.DotID()) + if bidTask.Result.Error != nil { + e.lggr.Warnw(fmt.Sprintf("got error for enhanced EA telemetry bid price, job %d, id %s: %s", e.job.ID, bidTask.Task.DotID(), bidTask.Result.Error), "err", bidTask.Result.Error) + } else { + bidPrice, err = getResultFloat64(bidTask) + if err != nil { + e.lggr.Warnw(fmt.Sprintf("cannot parse enhanced EA telemetry bid price, job %d, id %s", e.job.ID, bidTask.Task.DotID()), "err", err) + } } } askTask := allTasks.GetNextTaskOf(*bidTask) if askTask == nil { e.lggr.Warnf("cannot parse enhanced EA telemetry ask price, task is nil, job %d, id %s", e.job.ID) - return 0, 0, 0 + return benchmarkPrice, bidPrice, 0 } if askTask.Task.Type() == pipeline.TaskTypeJSONParse { - askPrice, ok = askTask.Result.Value.(float64) - if !ok { - e.lggr.Warnf("cannot parse enhanced EA telemetry ask price, job %d, id %s", e.job.ID, askTask.Task.DotID()) + if bidTask.Result.Error != nil { + e.lggr.Warnw(fmt.Sprintf("got error for enhanced EA telemetry ask price, job %d, id %s: %s", e.job.ID, askTask.Task.DotID(), askTask.Result.Error), "err", askTask.Result.Error) + } else { + askPrice, err = getResultFloat64(askTask) + if err != nil { + e.lggr.Warnw(fmt.Sprintf("cannot parse enhanced EA telemetry ask price, job %d, id %s", e.job.ID, askTask.Task.DotID()), "err", err) + } } } @@ -418,3 +431,13 @@ func EnqueueEnhancedTelem[T EnhancedTelemetryData | EnhancedTelemetryMercuryData default: } } + +// getResultFloat64 will check the result type and force it to float64 or returns an error if the conversion cannot be made +func getResultFloat64(task *pipeline.TaskRunResult) (float64, error) { + result, err := utils.ToDecimal(task.Result.Value) + if err != nil { + return 0, err + } + resultFloat64, _ := result.Float64() + return resultFloat64, nil +} diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index e7c41c46761..88fb7de3e39 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -186,13 +186,13 @@ func TestGetJsonParsedValue(t *testing.T) { func TestSendEATelemetry(t *testing.T) { wg := sync.WaitGroup{} - ingressClient := mocks.NewTelemetryIngressClient(t) + ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA) + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA, "test-network", "test-chainID") var sentMessage []byte - ingressClient.On("Send", mock.AnythingOfType("synchronization.TelemPayload")).Return().Run(func(args mock.Arguments) { - sentMessage = args[0].(synchronization.TelemPayload).Telemetry + ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + sentMessage = args[1].([]byte) wg.Done() }) @@ -302,10 +302,10 @@ func TestGetObservation(t *testing.T) { func TestCollectAndSend(t *testing.T) { wg := sync.WaitGroup{} - ingressClient := mocks.NewTelemetryIngressClient(t) + ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA) - ingressClient.On("Send", mock.AnythingOfType("synchronization.TelemPayload")).Return().Run(func(args mock.Arguments) { + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEA, "test-network", "test-chainID") + ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { wg.Done() }) @@ -416,7 +416,7 @@ var trrsMercury = pipeline.TaskRunResults{ BaseTask: pipeline.NewBaseTask(3, "ds3_ask", nil, nil, 3), }, Result: pipeline.Result{ - Value: float64(123456789.1), + Value: int64(321123), }, }, } @@ -461,7 +461,7 @@ func TestGetPricesFromResults(t *testing.T) { benchmarkPrice, bid, ask := e.getPricesFromResults(trrsMercury[0], &trrsMercury) require.Equal(t, 123456.123456, benchmarkPrice) require.Equal(t, 1234567.1234567, bid) - require.Equal(t, 123456789.1, ask) + require.Equal(t, float64(321123), ask) benchmarkPrice, bid, ask = e.getPricesFromResults(trrsMercury[0], &pipeline.TaskRunResults{}) require.Equal(t, float64(0), benchmarkPrice) @@ -549,13 +549,13 @@ func TestGetAssetSymbolFromRequestData(t *testing.T) { func TestCollectMercuryEnhancedTelemetry(t *testing.T) { wg := sync.WaitGroup{} - ingressClient := mocks.NewTelemetryIngressClient(t) + ingressClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(ingressClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEAMercury) + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.EnhancedEAMercury, "test-network", "test-chainID") var sentMessage []byte - ingressClient.On("Send", mock.AnythingOfType("synchronization.TelemPayload")).Return().Run(func(args mock.Arguments) { - sentMessage = args[0].(synchronization.TelemPayload).Telemetry + ingressClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + sentMessage = args[1].([]byte) wg.Done() }) @@ -601,7 +601,7 @@ func TestCollectMercuryEnhancedTelemetry(t *testing.T) { DataSource: "data-source-name", DpBenchmarkPrice: 123456.123456, DpBid: 1234567.1234567, - DpAsk: 123456789.1, + DpAsk: 321123, CurrentBlockNumber: 123456789, CurrentBlockHash: common.HexToHash("0x123321").String(), CurrentBlockTimestamp: 987654321, diff --git a/core/services/ocrcommon/transmitter.go b/core/services/ocrcommon/transmitter.go index 24e985048f0..9cdf6a0c5a9 100644 --- a/core/services/ocrcommon/transmitter.go +++ b/core/services/ocrcommon/transmitter.go @@ -9,7 +9,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type roundRobinKeystore interface { @@ -17,7 +16,7 @@ type roundRobinKeystore interface { } type txManager interface { - CreateTransaction(txRequest txmgr.TxRequest, qopts ...pg.QOpt) (tx txmgr.Tx, err error) + CreateTransaction(ctx context.Context, txRequest txmgr.TxRequest) (tx txmgr.Tx, err error) } type Transmitter interface { @@ -72,7 +71,7 @@ func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") } - _, err = t.txm.CreateTransaction(txmgr.TxRequest{ + _, err = t.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: roundRobinFromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -81,7 +80,7 @@ func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common Strategy: t.strategy, Checker: t.checker, Meta: txMeta, - }, pg.WithParentCtx(ctx)) + }) return errors.Wrap(err, "skipped OCR transmission") } diff --git a/core/services/ocrcommon/transmitter_pipeline_test.go b/core/services/ocrcommon/transmitter_pipeline_test.go index 84294a1dde6..8a1f2f2a922 100644 --- a/core/services/ocrcommon/transmitter_pipeline_test.go +++ b/core/services/ocrcommon/transmitter_pipeline_test.go @@ -26,7 +26,7 @@ func Test_PipelineTransmitter_CreateEthTransaction(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) chainID := "12345" gasLimit := uint32(1000) diff --git a/core/services/ocrcommon/transmitter_test.go b/core/services/ocrcommon/transmitter_test.go index 65a5f382830..ac5d120eb0d 100644 --- a/core/services/ocrcommon/transmitter_test.go +++ b/core/services/ocrcommon/transmitter_test.go @@ -29,7 +29,7 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) @@ -51,7 +51,7 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { ) require.NoError(t, err) - txm.On("CreateTransaction", txmgr.TxRequest{ + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -59,7 +59,7 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { ForwarderAddress: common.Address{}, Meta: nil, Strategy: strategy, - }, mock.Anything).Return(txmgr.Tx{}, nil).Once() + }).Return(txmgr.Tx{}, nil).Once() require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) } @@ -70,8 +70,8 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) @@ -93,7 +93,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. ) require.NoError(t, err) - txm.On("CreateTransaction", txmgr.TxRequest{ + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, @@ -101,8 +101,8 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. ForwarderAddress: common.Address{}, Meta: nil, Strategy: strategy, - }, mock.Anything).Return(txmgr.Tx{}, nil).Once() - txm.On("CreateTransaction", txmgr.TxRequest{ + }).Return(txmgr.Tx{}, nil).Once() + txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: fromAddress2, ToAddress: toAddress, EncodedPayload: payload, @@ -110,7 +110,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. ForwarderAddress: common.Address{}, Meta: nil, Strategy: strategy, - }, mock.Anything).Return(txmgr.Tx{}, nil).Once() + }).Return(txmgr.Tx{}, nil).Once() require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) } @@ -153,8 +153,8 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) gasLimit := uint32(1000) chainID := big.NewInt(0) diff --git a/core/services/pg/lease_lock_test.go b/core/services/pg/lease_lock_test.go index 7ef4e292b8c..9f857ffa20b 100644 --- a/core/services/pg/lease_lock_test.go +++ b/core/services/pg/lease_lock_test.go @@ -6,10 +6,11 @@ import ( "time" "github.com/google/uuid" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -48,8 +49,7 @@ func Test_LeaseLock(t *testing.T) { leaseLock2 := newLeaseLock(t, db, cfg) go func() { defer leaseLock2.Release() - err := leaseLock2.TakeAndHold(testutils.Context(t)) - require.NoError(t, err) + require.NoError(t, leaseLock2.TakeAndHold(testutils.Context(t))) close(started2) }() diff --git a/core/services/pg/mocks/event_broadcaster.go b/core/services/pg/mocks/event_broadcaster.go index 863255c731d..b4d04b8b999 100644 --- a/core/services/pg/mocks/event_broadcaster.go +++ b/core/services/pg/mocks/event_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -126,13 +126,12 @@ func (_m *EventBroadcaster) Subscribe(channel string, payloadFilter string) (pg. return r0, r1 } -type mockConstructorTestingTNewEventBroadcaster interface { +// NewEventBroadcaster creates a new instance of EventBroadcaster. 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 NewEventBroadcaster(t interface { mock.TestingT Cleanup(func()) -} - -// NewEventBroadcaster creates a new instance of EventBroadcaster. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewEventBroadcaster(t mockConstructorTestingTNewEventBroadcaster) *EventBroadcaster { +}) *EventBroadcaster { mock := &EventBroadcaster{} mock.Mock.Test(t) diff --git a/core/services/pg/mocks/subscription.go b/core/services/pg/mocks/subscription.go index ce5c93aacc2..9cfe4c4f020 100644 --- a/core/services/pg/mocks/subscription.go +++ b/core/services/pg/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -66,13 +66,12 @@ func (_m *Subscription) Send(event pg.Event) { _m.Called(event) } -type mockConstructorTestingTNewSubscription interface { +// NewSubscription creates a new instance of Subscription. 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 NewSubscription(t interface { mock.TestingT Cleanup(func()) -} - -// NewSubscription creates a new instance of Subscription. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSubscription(t mockConstructorTestingTNewSubscription) *Subscription { +}) *Subscription { mock := &Subscription{} mock.Mock.Test(t) diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 41643d42c97..9c70d813ab6 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -237,6 +237,15 @@ func (q Q) Select(dest interface{}, query string, args ...interface{}) error { return ql.withLogError(q.Queryer.SelectContext(ctx, dest, query, args...)) } + +func (q Q) SelectNamed(dest interface{}, query string, arg interface{}) error { + query, args, err := q.BindNamed(query, arg) + if err != nil { + return errors.Wrap(err, "error binding arg") + } + return q.Select(dest, query, args...) +} + func (q Q) Get(dest interface{}, query string, args ...interface{}) error { ctx, cancel := q.Context() defer cancel() @@ -247,6 +256,7 @@ func (q Q) Get(dest interface{}, query string, args ...interface{}) error { return ql.withLogError(q.Queryer.GetContext(ctx, dest, query, args...)) } + func (q Q) GetNamed(sql string, dest interface{}, arg interface{}) error { query, args, err := q.BindNamed(sql, arg) if err != nil { @@ -263,7 +273,9 @@ func (q Q) GetNamed(sql string, dest interface{}, arg interface{}) error { } func (q Q) newQueryLogger(query string, args []interface{}) *queryLogger { - return &queryLogger{Q: q, query: query, args: args} + return &queryLogger{Q: q, query: query, args: args, str: sync.OnceValue(func() string { + return sprintQ(query, args) + })} } // sprintQ formats the query with the given args and returns the resulting string. @@ -305,15 +317,11 @@ type queryLogger struct { query string args []interface{} - str string - strOnce sync.Once + str func() string } func (q *queryLogger) String() string { - q.strOnce.Do(func() { - q.str = sprintQ(q.query, q.args) - }) - return q.str + return q.str() } func (q *queryLogger) logSqlQuery() { diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index 261ebd9ab18..eb9a411f423 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -84,13 +84,12 @@ func (_m *Config) ReaperThreshold() time.Duration { return r0 } -type mockConstructorTestingTNewConfig interface { +// NewConfig creates a new instance of Config. 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 NewConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { +}) *Config { mock := &Config{} mock.Mock.Test(t) diff --git a/core/services/pipeline/mocks/orm.go b/core/services/pipeline/mocks/orm.go index 01def543b43..88d067c6ffa 100644 --- a/core/services/pipeline/mocks/orm.go +++ b/core/services/pipeline/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -377,13 +377,12 @@ func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pi return r0, r1, r2 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go index 62b89f239f4..3478ce1322d 100644 --- a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go +++ b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -23,13 +23,12 @@ func (_m *PipelineParamUnmarshaler) UnmarshalPipelineParam(val interface{}) erro return r0 } -type mockConstructorTestingTNewPipelineParamUnmarshaler interface { +// NewPipelineParamUnmarshaler creates a new instance of PipelineParamUnmarshaler. 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 NewPipelineParamUnmarshaler(t interface { mock.TestingT Cleanup(func()) -} - -// NewPipelineParamUnmarshaler creates a new instance of PipelineParamUnmarshaler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewPipelineParamUnmarshaler(t mockConstructorTestingTNewPipelineParamUnmarshaler) *PipelineParamUnmarshaler { +}) *PipelineParamUnmarshaler { mock := &PipelineParamUnmarshaler{} mock.Mock.Test(t) diff --git a/core/services/pipeline/mocks/runner.go b/core/services/pipeline/mocks/runner.go index e2cc70378e5..34b55399752 100644 --- a/core/services/pipeline/mocks/runner.go +++ b/core/services/pipeline/mocks/runner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -243,13 +243,12 @@ func (_m *Runner) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewRunner interface { +// NewRunner creates a new instance of Runner. 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 NewRunner(t interface { mock.TestingT Cleanup(func()) -} - -// NewRunner creates a new instance of Runner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRunner(t mockConstructorTestingTNewRunner) *Runner { +}) *Runner { mock := &Runner{} mock.Mock.Test(t) diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 3366a177ba8..20319682ef6 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -98,7 +98,7 @@ var ( Name: "pipeline_tasks_total_finished", Help: "The total number of pipeline tasks which have finished", }, - []string{"job_id", "job_name", "task_id", "task_type", "status"}, + []string{"job_id", "job_name", "task_id", "task_type", "bridge_name", "status"}, ) ) @@ -488,7 +488,13 @@ func logTaskRunToPrometheus(trr TaskRunResult, spec Spec) { } else { status = "completed" } - PromPipelineTasksTotalFinished.WithLabelValues(fmt.Sprintf("%d", spec.JobID), spec.JobName, trr.Task.DotID(), string(trr.Task.Type()), status).Inc() + + bridgeName := "" + if bridgeTask, ok := trr.Task.(*BridgeTask); ok { + bridgeName = bridgeTask.Name + } + + PromPipelineTasksTotalFinished.WithLabelValues(fmt.Sprintf("%d", spec.JobID), spec.JobName, trr.Task.DotID(), string(trr.Task.Type()), bridgeName, status).Inc() } // ExecuteAndInsertFinishedRun executes a run in memory then inserts the finished run/task run records, returning the final result diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index e37b2095236..6f542d485e0 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -138,7 +138,7 @@ func fakeIntermittentlyFailingPriceResponder(t *testing.T, requestData map[strin if reqBody.Meta["shouldFail"].(bool) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadGateway) - require.NoError(t, json.NewEncoder(w).Encode(errors.New("EA failure!"))) + require.NoError(t, json.NewEncoder(w).Encode(errors.New("EA failure"))) return } w.Header().Set("Content-Type", "application/json") diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index d5d29240652..57f1c0a7ed8 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -63,7 +63,7 @@ func (t *ETHTxTask) getEvmChainID() string { return t.EVMChainID } -func (t *ETHTxTask) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { +func (t *ETHTxTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { var chainID StringParam err := errors.Wrap(ResolveParam(&chainID, From(VarExpr(t.getEvmChainID(), vars), NonemptyString(t.getEvmChainID()), "")), "evmChainID") if err != nil { @@ -163,7 +163,7 @@ func (t *ETHTxTask) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs txRequest.MinConfirmations = clnull.Uint32From(uint32(minOutgoingConfirmations)) } - _, err = txManager.CreateTransaction(txRequest) + _, err = txManager.CreateTransaction(ctx, txRequest) if err != nil { return Result{Error: errors.Wrapf(ErrTaskRunFailed, "while creating transaction: %v", err)}, retryableRunInfo() } diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index a280e6f2720..af09d793852 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -84,7 +84,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -131,7 +131,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -166,9 +166,9 @@ func TestETHTxTask(t *testing.T) { }), nil, func(keyStore *keystoremocks.Eth, txManager *txmmocks.MockEvmTxManager) { - from := common.HexToAddress("0x882969652440ccf14a5dbb9bd53eb21cb1e11e5c") - keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", mock.MatchedBy(func(tx txmgr.TxRequest) bool { + addr := common.HexToAddress("0x882969652440ccf14a5dbb9bd53eb21cb1e11e5c") + keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, addr).Return(addr, nil) + txManager.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.MinConfirmations == clnull.Uint32From(2) })).Return(txmgr.Tx{}, nil) }, @@ -208,7 +208,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -253,7 +253,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -283,7 +283,7 @@ func TestETHTxTask(t *testing.T) { gasLimit := uint32(12345) txMeta := &txmgr.TxMeta{FailOnRevert: null.BoolFrom(false)} keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -317,7 +317,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -351,7 +351,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -416,7 +416,7 @@ func TestETHTxTask(t *testing.T) { FailOnRevert: null.BoolFrom(false), } keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", txmgr.TxRequest{ + txManager.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ FromAddress: from, ToAddress: to, EncodedPayload: data, @@ -512,7 +512,7 @@ func TestETHTxTask(t *testing.T) { func(keyStore *keystoremocks.Eth, txManager *txmmocks.MockEvmTxManager) { from := common.HexToAddress("0x882969652440ccf14a5dbb9bd53eb21cb1e11e5c") keyStore.On("GetRoundRobinAddress", testutils.FixtureChainID, from).Return(from, nil) - txManager.On("CreateTransaction", mock.MatchedBy(func(tx txmgr.TxRequest) bool { + txManager.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { return tx.MinConfirmations == clnull.Uint32From(3) && tx.PipelineTaskRunID != nil })).Return(txmgr.Tx{}, nil) }, diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 9629045cb0b..f57cf8f45a8 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -6,19 +6,18 @@ import ( "testing" "time" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" - "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -59,7 +58,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - _, fromAddress := cltest.MustAddRandomKeyToKeystore(t, ethKeyStore) + _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) var subscribeCalls atomic.Int32 diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 73c16a19596..0a433c3bc54 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -87,7 +87,7 @@ func TestConfigPoller(t *testing.T) { ethClient = evmclient.NewSimulatedBackendClient(t, b, testutils.SimulatedChainID) ctx := testutils.Context(t) lorm := logpoller.NewORM(testutils.SimulatedChainID, db, lggr, cfg) - lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) + lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) require.NoError(t, lp.Start(ctx)) t.Cleanup(func() { lp.Close() }) } diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 6ae2052c408..e7a2bca3448 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -11,22 +11,22 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" pkgerrors "github.com/pkg/errors" + "go.uber.org/multierr" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median/evmreportcodec" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/sqlx" - "go.uber.org/multierr" - "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -45,7 +45,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ relaytypes.Relayer = &Relayer{} +var _ relaytypes.Relayer = &Relayer{} //nolint:staticcheck type Relayer struct { db *sqlx.DB @@ -127,11 +127,12 @@ func (r *Relayer) Ready() error { func (r *Relayer) HealthReport() (report map[string]error) { report = make(map[string]error) - maps.Copy(report, r.mercuryPool.HealthReport()) + services.CopyHealth(report, r.mercuryPool.HealthReport()) return } func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.MercuryProvider, error) { + lggr := r.lggr.Named("MercuryProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -139,7 +140,7 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype } var mercuryConfig mercuryconfig.PluginConfig - if err := json.Unmarshal(pargs.PluginConfig, &mercuryConfig); err != nil { + if err = json.Unmarshal(pargs.PluginConfig, &mercuryConfig); err != nil { return nil, pkgerrors.WithStack(err) } @@ -151,7 +152,7 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype if relayConfig.ChainID.String() != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - configWatcher, err := newConfigProvider(r.lggr, r.chain, relayOpts, r.eventBroadcaster) + cw, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) if err != nil { return nil, pkgerrors.WithStack(err) } @@ -172,9 +173,9 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype // FIXME: We actually know the version here since it's in the feed ID, can // we use generics to avoid passing three of this? // https://smartcontract-it.atlassian.net/browse/MERC-1414 - reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV1")) - reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV2")) - reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, r.lggr.Named("ReportCodecV3")) + reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV1")) + reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV2")) + reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV3")) var transmitterCodec mercury.TransmitterReportDecoder switch feedID.Version() { @@ -187,17 +188,19 @@ func (r *Relayer) NewMercuryProvider(rargs relaytypes.RelayArgs, pargs relaytype default: return nil, fmt.Errorf("invalid feed version %d", feedID.Version()) } - transmitter := mercury.NewTransmitter(r.lggr, configWatcher.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) + transmitter := mercury.NewTransmitter(lggr, cw.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) - return NewMercuryProvider(configWatcher, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, r.lggr), nil + return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil } func (r *Relayer) NewFunctionsProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.FunctionsProvider, error) { + lggr := r.lggr.Named("FunctionsProvider").Named(rargs.ExternalJobID.String()) // TODO(FUN-668): Not ready yet (doesn't implement FunctionsEvents() properly) - return NewFunctionsProvider(r.chain, rargs, pargs, r.lggr, r.ks.Eth(), functions.FunctionsPlugin) + return NewFunctionsProvider(r.chain, rargs, pargs, lggr, r.ks.Eth(), functions.FunctionsPlugin) } func (r *Relayer) NewConfigProvider(args relaytypes.RelayArgs) (relaytypes.ConfigProvider, error) { + lggr := r.lggr.Named("ConfigProvider").Named(args.ExternalJobID.String()) relayOpts := types.NewRelayOpts(args) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -208,7 +211,7 @@ func (r *Relayer) NewConfigProvider(args relaytypes.RelayArgs) (relaytypes.Confi return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - configProvider, err := newConfigProvider(r.lggr, r.chain, relayOpts, r.eventBroadcaster) + configProvider, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) if err != nil { // Never return (*configProvider)(nil) return nil, err @@ -261,7 +264,7 @@ func newConfigWatcher(lggr logger.Logger, replayCtx, replayCancel := context.WithCancel(context.Background()) return &configWatcher{ StartStopOnce: utils.StartStopOnce{}, - lggr: lggr, + lggr: lggr.Named("ConfigWatcher").Named(contractAddress.String()), contractAddress: contractAddress, contractABI: contractABI, offchainDigester: offchainDigester, @@ -338,7 +341,7 @@ func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpt } if relayConfig.FeedID != nil { cp, err = mercury.NewConfigPoller( - lggr, + lggr.Named(relayConfig.FeedID.String()), chain.LogPoller(), aggregatorAddress, *relayConfig.FeedID, @@ -491,6 +494,7 @@ func newPipelineContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayAr } func (r *Relayer) NewMedianProvider(rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs) (relaytypes.MedianProvider, error) { + lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -501,18 +505,18 @@ func (r *Relayer) NewMedianProvider(rargs relaytypes.RelayArgs, pargs relaytypes return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - configWatcher, err := newConfigProvider(r.lggr, r.chain, relayOpts, r.eventBroadcaster) + configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) if err != nil { return nil, err } reportCodec := evmreportcodec.ReportCodec{} - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, configWatcher, r.ks.Eth()) + contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, configWatcher, r.ks.Eth()) if err != nil { return nil, err } - medianContract, err := newMedianContract(configWatcher.ContractConfigTracker(), configWatcher.contractAddress, configWatcher.chain, rargs.JobID, r.db, r.lggr) + medianContract, err := newMedianContract(configWatcher.ContractConfigTracker(), configWatcher.contractAddress, configWatcher.chain, rargs.JobID, r.db, lggr) if err != nil { return nil, err } @@ -553,7 +557,7 @@ func (p *medianProvider) Ready() error { func (p *medianProvider) HealthReport() map[string]error { report := p.configWatcher.HealthReport() - maps.Copy(report, p.contractTransmitter.HealthReport()) + services.CopyHealth(report, p.contractTransmitter.HealthReport()) return report } diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index d6573ef3544..085f0c6e317 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -80,7 +80,7 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig lggr := logger.TestLogger(t) ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) - lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) + lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) defer lp.Close() require.NoError(t, lp.Start(ctx)) configPoller, err := functions.NewFunctionsConfigPoller(pluginType, lp, lggr) diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index 648cbcc2606..17baab4525c 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -76,6 +76,10 @@ func NewFunctionsContractTransmitter( return nil, errors.New("invalid ABI, missing transmitted") } + if contractVersion != 1 { + return nil, fmt.Errorf("unsupported contract version: %d", contractVersion) + } + if reportToEvmTxMeta == nil { reportToEvmTxMeta = reportToEvmTxMetaNoop } @@ -121,13 +125,7 @@ func (oc *contractTransmitter) Transmit(ctx context.Context, reportCtx ocrtypes. } var destinationContract common.Address - if oc.contractVersion == 0 { - destinationContractPtr := oc.contractAddress.Load() - if destinationContractPtr == nil { - return errors.New("destination contract address not set") - } - destinationContract = *destinationContractPtr - } else if oc.contractVersion == 1 { + if oc.contractVersion == 1 { oc.lggr.Debugw("FunctionsContractTransmitter: start", "reportLenBytes", len(report)) requests, err2 := oc.reportCodec.DecodeReport(report) if err2 != nil { diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index 6b227bcdd50..c9dc942c5df 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -52,7 +52,7 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { functionsTransmitter, err := functions.NewFunctionsContractTransmitter(c, contractABI, &mockTransmitter{}, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { return &txmgr.TxMeta{}, nil - }, 0) + }, 1) require.NoError(t, err) require.NoError(t, functionsTransmitter.UpdateRoutes(gethcommon.Address{}, gethcommon.Address{})) @@ -62,29 +62,6 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { assert.Equal(t, uint32(2), epoch) } -func TestContractTransmitter_Transmit_V0(t *testing.T) { - t.Parallel() - - contractVersion := uint32(0) - destAddress := testutils.NewAddress() - lggr := logger.TestLogger(t) - c := evmclimocks.NewClient(t) - lp := lpmocks.NewLogPoller(t) - contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) - require.NoError(t, err) - lp.On("RegisterFilter", mock.Anything).Return(nil) - - ocrTransmitter := mockTransmitter{} - ot, err := functions.NewFunctionsContractTransmitter(c, contractABI, &ocrTransmitter, lp, lggr, func(b []byte) (*txmgr.TxMeta, error) { - return &txmgr.TxMeta{}, nil - }, contractVersion) - require.NoError(t, err) - require.NoError(t, ot.UpdateRoutes(destAddress, destAddress)) - - require.NoError(t, ot.Transmit(testutils.Context(t), ocrtypes.ReportContext{}, []byte("bar"), []ocrtypes.AttributedOnchainSignature{})) - require.Equal(t, destAddress, ocrTransmitter.toAddress) -} - func TestContractTransmitter_Transmit_V1(t *testing.T) { t.Parallel() diff --git a/core/services/relay/evm/loop_impl.go b/core/services/relay/evm/loop_impl.go index 8142721ed16..f69660373e6 100644 --- a/core/services/relay/evm/loop_impl.go +++ b/core/services/relay/evm/loop_impl.go @@ -20,7 +20,7 @@ type LoopRelayer struct { var _ loop.Relayer = &LoopRelayer{} func NewLoopRelayServerAdapter(r *Relayer, cs EVMChainRelayerExtender) *LoopRelayer { - ra := relay.NewRelayerServerAdapter(r, cs) + ra := relay.NewServerAdapter(r, cs) return &LoopRelayer{ Relayer: ra, ext: cs, diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 4e3587b5de6..3a58a25a557 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -169,7 +169,7 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { lggr := logger.TestLogger(t) ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) - lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) + lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) eventBroadcaster := pgmocks.NewEventBroadcaster(t) subscription := pgmocks.NewSubscription(t) require.NoError(t, lp.Start(ctx)) diff --git a/core/services/relay/evm/mercury/mocks/async_deleter.go b/core/services/relay/evm/mercury/mocks/async_deleter.go index 951f3d4bee9..c0f583efd18 100644 --- a/core/services/relay/evm/mercury/mocks/async_deleter.go +++ b/core/services/relay/evm/mercury/mocks/async_deleter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -17,13 +17,12 @@ func (_m *AsyncDeleter) AsyncDelete(req *pb.TransmitRequest) { _m.Called(req) } -type mockConstructorTestingTNewAsyncDeleter interface { +// NewAsyncDeleter creates a new instance of AsyncDeleter. 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 NewAsyncDeleter(t interface { mock.TestingT Cleanup(func()) -} - -// NewAsyncDeleter creates a new instance of AsyncDeleter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAsyncDeleter(t mockConstructorTestingTNewAsyncDeleter) *AsyncDeleter { +}) *AsyncDeleter { mock := &AsyncDeleter{} mock.Mock.Test(t) diff --git a/core/services/relay/evm/mercury/mocks/chain_head_tracker.go b/core/services/relay/evm/mercury/mocks/chain_head_tracker.go index 84d74673cbc..1a5a7e47c5b 100644 --- a/core/services/relay/evm/mercury/mocks/chain_head_tracker.go +++ b/core/services/relay/evm/mercury/mocks/chain_head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -50,13 +50,12 @@ func (_m *ChainHeadTracker) HeadTracker() commontypes.HeadTracker[*evmtypes.Head return r0 } -type mockConstructorTestingTNewChainHeadTracker interface { +// NewChainHeadTracker creates a new instance of ChainHeadTracker. 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 NewChainHeadTracker(t interface { mock.TestingT Cleanup(func()) -} - -// NewChainHeadTracker creates a new instance of ChainHeadTracker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewChainHeadTracker(t mockConstructorTestingTNewChainHeadTracker) *ChainHeadTracker { +}) *ChainHeadTracker { mock := &ChainHeadTracker{} mock.Mock.Test(t) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index 199dbfcdf88..0c701e3b4b3 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -15,14 +15,15 @@ import ( pkgerrors "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/sqlx" - "golang.org/x/exp/maps" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" + "github.com/smartcontractkit/chainlink-relay/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" @@ -69,7 +70,7 @@ var ( type Transmitter interface { relaymercury.Transmitter - services.ServiceCtx + services.Service } type ConfigTracker interface { @@ -182,14 +183,12 @@ func (mt *mercuryTransmitter) Close() error { }) } -func (mt *mercuryTransmitter) Ready() error { return mt.StartStopOnce.Ready() } - func (mt *mercuryTransmitter) Name() string { return mt.lggr.Name() } func (mt *mercuryTransmitter) HealthReport() map[string]error { - report := map[string]error{mt.Name(): mt.StartStopOnce.Healthy()} - maps.Copy(report, mt.rpcClient.HealthReport()) - maps.Copy(report, mt.queue.HealthReport()) + report := map[string]error{mt.Name(): mt.Healthy()} + services.CopyHealth(report, mt.rpcClient.HealthReport()) + services.CopyHealth(report, mt.queue.HealthReport()) return report } diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index caeae8d278a..10c8839a3c5 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -208,11 +208,12 @@ func setBenchmarkPrice(o *parseOutput, res pipeline.Result) error { if res.Error != nil { o.benchmarkPrice.Err = res.Error return res.Error - } else if val, err := toBigInt(res.Value); err != nil { + } + val, err := toBigInt(res.Value) + if err != nil { return fmt.Errorf("failed to parse BenchmarkPrice: %w", err) - } else { - o.benchmarkPrice.Val = val } + o.benchmarkPrice.Val = val return nil } diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index 79f6c536efd..4eadfc35c23 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -222,11 +222,12 @@ func setBenchmarkPrice(o *parseOutput, res pipeline.Result) error { if res.Error != nil { o.benchmarkPrice.Err = res.Error return res.Error - } else if val, err := toBigInt(res.Value); err != nil { + } + val, err := toBigInt(res.Value) + if err != nil { return fmt.Errorf("failed to parse BenchmarkPrice: %w", err) - } else { - o.benchmarkPrice.Val = val } + o.benchmarkPrice.Val = val return nil } @@ -234,11 +235,12 @@ func setBid(o *parseOutput, res pipeline.Result) error { if res.Error != nil { o.bid.Err = res.Error return res.Error - } else if val, err := toBigInt(res.Value); err != nil { + } + val, err := toBigInt(res.Value) + if err != nil { return fmt.Errorf("failed to parse Bid: %w", err) - } else { - o.bid.Val = val } + o.bid.Val = val return nil } @@ -246,11 +248,12 @@ func setAsk(o *parseOutput, res pipeline.Result) error { if res.Error != nil { o.ask.Err = res.Error return res.Error - } else if val, err := toBigInt(res.Value); err != nil { + } + val, err := toBigInt(res.Value) + if err != nil { return fmt.Errorf("failed to parse Ask: %w", err) - } else { - o.ask.Val = val } + o.ask.Val = val return nil } diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 74072167061..914401c0897 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -4,18 +4,16 @@ import ( "context" "errors" - "golang.org/x/exp/maps" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" relaymercury "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury" relaymercuryv1 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v1" relaymercuryv2 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v2" relaymercuryv3 "github.com/smartcontractkit/chainlink-relay/pkg/reportingplugins/mercury/v3" + "github.com/smartcontractkit/chainlink-relay/pkg/services" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" ) @@ -69,8 +67,8 @@ func (p *mercuryProvider) Name() string { func (p *mercuryProvider) HealthReport() map[string]error { report := map[string]error{} - maps.Copy(report, p.configWatcher.HealthReport()) - maps.Copy(report, p.transmitter.HealthReport()) + services.CopyHealth(report, p.configWatcher.HealthReport()) + services.CopyHealth(report, p.transmitter.HealthReport()) return report } diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 11150874b9e..13107fe8ae5 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -235,13 +235,12 @@ func (_m *LoopRelayAdapter) Transact(ctx context.Context, from string, to string return r0 } -type mockConstructorTestingTNewLoopRelayAdapter interface { +// NewLoopRelayAdapter creates a new instance of LoopRelayAdapter. 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 NewLoopRelayAdapter(t interface { mock.TestingT Cleanup(func()) -} - -// NewLoopRelayAdapter creates a new instance of LoopRelayAdapter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLoopRelayAdapter(t mockConstructorTestingTNewLoopRelayAdapter) *LoopRelayAdapter { +}) *LoopRelayAdapter { mock := &LoopRelayAdapter{} mock.Mock.Test(t) diff --git a/core/services/relay/evm/mocks/request_round_db.go b/core/services/relay/evm/mocks/request_round_db.go index ead179b1de8..1727e8cc47d 100644 --- a/core/services/relay/evm/mocks/request_round_db.go +++ b/core/services/relay/evm/mocks/request_round_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -51,13 +51,12 @@ func (_m *RequestRoundDB) SaveLatestRoundRequested(tx pg.Queryer, rr ocr2aggrega return r0 } -type mockConstructorTestingTNewRequestRoundDB interface { +// NewRequestRoundDB creates a new instance of RequestRoundDB. 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 NewRequestRoundDB(t interface { mock.TestingT Cleanup(func()) -} - -// NewRequestRoundDB creates a new instance of RequestRoundDB. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewRequestRoundDB(t mockConstructorTestingTNewRequestRoundDB) *RequestRoundDB { +}) *RequestRoundDB { mock := &RequestRoundDB{} mock.Mock.Test(t) diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index ce638d10cf9..b6ca4d75fb7 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -8,19 +8,19 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmchain "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) // ErrNoChains indicates that no EVM chains have been started var ErrNoChains = errors.New("no EVM chains loaded") type EVMChainRelayerExtender interface { - relay.RelayerExt + loop.RelayerExt Chain() evmchain.Chain } diff --git a/core/services/relay/evm/types/mocks/log_poller_wrapper.go b/core/services/relay/evm/types/mocks/log_poller_wrapper.go index a32df6500f3..6812ce5aba3 100644 --- a/core/services/relay/evm/types/mocks/log_poller_wrapper.go +++ b/core/services/relay/evm/types/mocks/log_poller_wrapper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -126,13 +126,12 @@ func (_m *LogPollerWrapper) SubscribeToUpdates(name string, subscriber types.Rou _m.Called(name, subscriber) } -type mockConstructorTestingTNewLogPollerWrapper interface { +// NewLogPollerWrapper creates a new instance of LogPollerWrapper. 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 NewLogPollerWrapper(t interface { mock.TestingT Cleanup(func()) -} - -// NewLogPollerWrapper creates a new instance of LogPollerWrapper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewLogPollerWrapper(t mockConstructorTestingTNewLogPollerWrapper) *LogPollerWrapper { +}) *LogPollerWrapper { mock := &LogPollerWrapper{} mock.Mock.Test(t) diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index 97eddd7d9cf..6a1e66bd096 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -13,6 +13,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-relay/pkg/services" "github.com/smartcontractkit/chainlink-relay/pkg/types" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" @@ -103,7 +104,7 @@ type RouteUpdateSubscriber interface { // //go:generate mockery --quiet --name LogPollerWrapper --output ./mocks/ --case=underscore type LogPollerWrapper interface { - relaytypes.Service + services.Service LatestEvents() ([]OracleRequest, []OracleResponse, error) // TODO (FUN-668): Remove from the LOOP interface and only use internally within the EVM relayer diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index 75ced101b3f..5c7bf5cab57 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -2,15 +2,11 @@ package relay import ( "context" - "errors" "fmt" "regexp" - "golang.org/x/exp/maps" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/services" ) type Network = string @@ -73,99 +69,18 @@ func (i *ID) UnmarshalString(s string) error { return nil } -// RelayerExt is a subset of [loop.Relayer] for adapting [types.Relayer], typically with a Chain. See [relayerAdapter]. -type RelayerExt interface { - types.ChainService - ID() string -} - -var _ loop.Relayer = (*relayerAdapter)(nil) - -// relayerAdapter adapts a [types.Relayer] and [RelayerExt] to implement [loop.Relayer]. -type relayerAdapter struct { - types.Relayer - RelayerExt -} - -// NewRelayerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. -// Unlike NewRelayerServerAdapter which is used to adapt non-LOOPP relayers, this is used to adapt -// LOOPP-based relayer which are then server over GRPC (by the relayerServer). -func NewRelayerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { - return &relayerAdapter{Relayer: r, RelayerExt: e} -} - -func (r *relayerAdapter) NewConfigProvider(ctx context.Context, rargs types.RelayArgs) (types.ConfigProvider, error) { - return r.Relayer.NewConfigProvider(rargs) -} - -func (r *relayerAdapter) NewMedianProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.MedianProvider, error) { - return r.Relayer.NewMedianProvider(rargs, pargs) -} - -func (r *relayerAdapter) NewMercuryProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.MercuryProvider, error) { - return r.Relayer.NewMercuryProvider(rargs, pargs) -} - -func (r *relayerAdapter) NewFunctionsProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.FunctionsProvider, error) { - return r.Relayer.NewFunctionsProvider(rargs, pargs) -} - -func (r *relayerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { - return nil, fmt.Errorf("unexpected call to NewPluginProvider: did you forget to wrap relayerAdapter in a relayerServerAdapter?") -} - -func (r *relayerAdapter) Start(ctx context.Context) error { - var ms services.MultiStart - return ms.Start(ctx, r.RelayerExt, r.Relayer) -} - -func (r *relayerAdapter) Close() error { - return services.CloseAll(r.Relayer, r.RelayerExt) -} - -func (r *relayerAdapter) Name() string { - return fmt.Sprintf("%s-%s", r.Relayer.Name(), r.RelayerExt.Name()) -} - -func (r *relayerAdapter) Ready() (err error) { - return errors.Join(r.Relayer.Ready(), r.RelayerExt.Ready()) -} - -func (r *relayerAdapter) HealthReport() map[string]error { - hr := make(map[string]error) - maps.Copy(hr, r.Relayer.HealthReport()) - maps.Copy(hr, r.RelayerExt.HealthReport()) - return hr -} - -func (r *relayerAdapter) NodeStatuses(ctx context.Context, offset, limit int, chainIDs ...string) (nodes []types.NodeStatus, total int, err error) { - if len(chainIDs) > 1 { - return nil, 0, fmt.Errorf("internal error: node statuses expects at most one chain id got %v", chainIDs) - } - if len(chainIDs) == 1 && chainIDs[0] != r.ID() { - return nil, 0, fmt.Errorf("node statuses unexpected chain id got %s want %s", chainIDs[0], r.ID()) - } - - nodes, _, total, err = r.ListNodeStatuses(ctx, int32(limit), "") - if err != nil { - return nil, 0, err - } - if len(nodes) < offset { - return []types.NodeStatus{}, 0, fmt.Errorf("out of range") - } - if limit <= 0 { - limit = len(nodes) - } else if len(nodes) < limit { - limit = len(nodes) - } - return nodes[offset:limit], total, nil +// ServerAdapter extends [loop.RelayerAdapter] by overriding NewPluginProvider to dispatches calls according to `RelayArgs.ProviderType`. +// This should only be used to adapt relayers not running via GRPC in a LOOPP. +type ServerAdapter struct { + loop.RelayerAdapter } -type relayerServerAdapter struct { - *relayerAdapter +// NewServerAdapter returns a new ServerAdapter. +func NewServerAdapter(r types.Relayer, e loop.RelayerExt) *ServerAdapter { //nolint:staticcheck + return &ServerAdapter{RelayerAdapter: loop.RelayerAdapter{Relayer: r, RelayerExt: e}} } -func (r *relayerServerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { +func (r *ServerAdapter) NewPluginProvider(ctx context.Context, rargs types.RelayArgs, pargs types.PluginArgs) (types.PluginProvider, error) { switch types.OCR2PluginType(rargs.ProviderType) { case types.Median: return r.NewMedianProvider(ctx, rargs, pargs) @@ -174,19 +89,9 @@ func (r *relayerServerAdapter) NewPluginProvider(ctx context.Context, rargs type case types.Mercury: return r.NewMercuryProvider(ctx, rargs, pargs) case types.DKG, types.OCR2VRF, types.OCR2Keeper, types.GenericPlugin: - return r.relayerAdapter.NewPluginProvider(ctx, rargs, pargs) + return r.RelayerAdapter.NewPluginProvider(ctx, rargs, pargs) + case types.CCIPCommit, types.CCIPExecution: + return nil, fmt.Errorf("provider type not supported: %s", rargs.ProviderType) } - - return nil, fmt.Errorf("provider type not supported: %s", rargs.ProviderType) -} - -// NewRelayerServerAdapter returns a [loop.Relayer] adapted from a [types.Relayer] and [RelayerExt]. -// Unlike NewRelayerAdapter, this behaves like the loop `RelayerServer` and dispatches calls -// to `NewPluginProvider` according to the passed in `RelayArgs.ProviderType`. -// This should only be used to adapt relayers not running via GRPC in a LOOPP. -// -// nolint:staticcheck // SA1019 -func NewRelayerServerAdapter(r types.Relayer, e RelayerExt) loop.Relayer { - ra := &relayerAdapter{Relayer: r, RelayerExt: e} - return &relayerServerAdapter{relayerAdapter: ra} + return nil, fmt.Errorf("provider type not recognized: %s", rargs.ProviderType) } diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 28ee0172c20..d3a94773498 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/types" ) @@ -85,7 +86,7 @@ func (m *mockRelayer) NewMercuryProvider(rargs types.RelayArgs, pargs types.Plug } type mockRelayerExt struct { - RelayerExt + loop.RelayerExt } func isType[T any](p any) bool { @@ -95,7 +96,7 @@ func isType[T any](p any) bool { func TestRelayerServerAdapter(t *testing.T) { r := &mockRelayer{} - sa := NewRelayerServerAdapter(r, mockRelayerExt{}) + sa := NewServerAdapter(r, mockRelayerExt{}) testCases := []struct { ProviderType string @@ -115,9 +116,17 @@ func TestRelayerServerAdapter(t *testing.T) { Test: isType[types.MercuryProvider], }, { - ProviderType: "unknown", + ProviderType: string(types.CCIPCommit), + Error: "provider type not supported", + }, + { + ProviderType: string(types.CCIPExecution), Error: "provider type not supported", }, + { + ProviderType: "unknown", + Error: "provider type not recognized", + }, { ProviderType: string(types.GenericPlugin), Error: "unexpected call to NewPluginProvider", diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index 8f4ae74ec36..f053af9ca7b 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -168,13 +168,12 @@ func (_m *ORM) Update(row *s4.Row, qopts ...pg.QOpt) error { return r0 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/services/s4/mocks/storage.go b/core/services/s4/mocks/storage.go index 1a10266fc81..f4174f171b8 100644 --- a/core/services/s4/mocks/storage.go +++ b/core/services/s4/mocks/storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -106,13 +106,12 @@ func (_m *Storage) Put(ctx context.Context, key *s4.Key, record *s4.Record, sign return r0 } -type mockConstructorTestingTNewStorage interface { +// NewStorage creates a new instance of Storage. 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 NewStorage(t interface { mock.TestingT Cleanup(func()) -} - -// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewStorage(t mockConstructorTestingTNewStorage) *Storage { +}) *Storage { mock := &Storage{} mock.Mock.Test(t) diff --git a/core/services/service.go b/core/services/service.go index 5bf61e062d2..066405ac012 100644 --- a/core/services/service.go +++ b/core/services/service.go @@ -1,85 +1,7 @@ package services -import "context" +import ( + "github.com/smartcontractkit/chainlink-relay/pkg/services" +) -// ServiceCtx represents a long-running service inside the Application. -// -// Typically, a ServiceCtx will leverage utils.StartStopOnce to implement these -// calls in a safe manner. -// -// # Template -// -// Mockable Foo service with a run loop -// -// //go:generate mockery --quiet --name Foo --output ../internal/mocks/ --case=underscore -// type ( -// // Expose a public interface so we can mock the service. -// Foo interface { -// service.ServiceCtx -// -// // ... -// } -// -// foo struct { -// // ... -// -// stop chan struct{} -// done chan struct{} -// -// utils.StartStopOnce -// } -// ) -// -// var _ Foo = (*foo)(nil) -// -// func NewFoo() Foo { -// f := &foo{ -// // ... -// } -// -// return f -// } -// -// func (f *foo) Start(ctx context.Context) error { -// return f.StartOnce("Foo", func() error { -// go f.run() -// -// return nil -// }) -// } -// -// func (f *foo) Close() error { -// return f.StopOnce("Foo", func() error { -// // trigger goroutine cleanup -// close(f.stop) -// // wait for cleanup to complete -// <-f.done -// return nil -// }) -// } -// -// func (f *foo) run() { -// // signal cleanup completion -// defer close(f.done) -// -// for { -// select { -// // ... -// case <-f.stop: -// // stop the routine -// return -// } -// } -// -// } -type ServiceCtx interface { - // Start the service. Must quit immediately if the context is cancelled. - // The given context applies to Start function only and must not be retained. - Start(context.Context) error - // Close stops the Service. - // Invariants: Usually after this call the Service cannot be started - // again, you need to build a new Service to do so. - Close() error - - Checkable -} +type ServiceCtx = services.Service diff --git a/core/services/synchronization/common.go b/core/services/synchronization/common.go index 2e36bc4d854..32f3a86c6f9 100644 --- a/core/services/synchronization/common.go +++ b/core/services/synchronization/common.go @@ -1,5 +1,11 @@ package synchronization +import ( + "context" + + "github.com/smartcontractkit/chainlink/v2/core/services" +) + // TelemetryType defines supported telemetry types type TelemetryType string @@ -17,3 +23,18 @@ const ( OCR2VRF TelemetryType = "ocr2-vrf" AutomationCustom TelemetryType = "automation-custom" ) + +type TelemPayload struct { + Telemetry []byte + TelemType TelemetryType + ContractID string +} + +// TelemetryService encapsulates all the functionality needed to +// send telemetry to the ingress server using wsrpc +// +//go:generate mockery --quiet --name TelemetryService --output ./mocks --case=underscore +type TelemetryService interface { + services.ServiceCtx + Send(ctx context.Context, telemetry []byte, contractID string, telemType TelemetryType) +} diff --git a/core/services/synchronization/helpers_test.go b/core/services/synchronization/helpers_test.go index da8f1bac5a8..14aaf5a7a02 100644 --- a/core/services/synchronization/helpers_test.go +++ b/core/services/synchronization/helpers_test.go @@ -11,14 +11,14 @@ import ( ) // NewTestTelemetryIngressClient calls NewTelemetryIngressClient and injects telemClient. -func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient) TelemetryIngressClient { +func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient) TelemetryService { tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100) tc.(*telemetryIngressClient).telemClient = telemClient return tc } // NewTestTelemetryIngressBatchClient calls NewTelemetryIngressBatchClient and injects telemClient. -func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryIngressBatchClient { +func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryService { tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn) tc.(*telemetryIngressBatchClient).close = func() error { return nil } tc.(*telemetryIngressBatchClient).telemClient = telemClient diff --git a/core/services/synchronization/mocks/telem_client.go b/core/services/synchronization/mocks/telem_client.go index 3ef3c00029d..a15614f157e 100644 --- a/core/services/synchronization/mocks/telem_client.go +++ b/core/services/synchronization/mocks/telem_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -66,13 +66,12 @@ func (_m *TelemClient) TelemBatch(ctx context.Context, in *telem.TelemBatchReque return r0, r1 } -type mockConstructorTestingTNewTelemClient interface { +// NewTelemClient creates a new instance of TelemClient. 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 NewTelemClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewTelemClient creates a new instance of TelemClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTelemClient(t mockConstructorTestingTNewTelemClient) *TelemClient { +}) *TelemClient { mock := &TelemClient{} mock.Mock.Test(t) diff --git a/core/services/synchronization/mocks/telemetry_ingress_batch_client.go b/core/services/synchronization/mocks/telemetry_ingress_batch_client.go deleted file mode 100644 index 4f992b0c79c..00000000000 --- a/core/services/synchronization/mocks/telemetry_ingress_batch_client.go +++ /dev/null @@ -1,107 +0,0 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. - -package mocks - -import ( - context "context" - - synchronization "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - mock "github.com/stretchr/testify/mock" -) - -// TelemetryIngressBatchClient is an autogenerated mock type for the TelemetryIngressBatchClient type -type TelemetryIngressBatchClient struct { - mock.Mock -} - -// Close provides a mock function with given fields: -func (_m *TelemetryIngressBatchClient) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// HealthReport provides a mock function with given fields: -func (_m *TelemetryIngressBatchClient) HealthReport() map[string]error { - ret := _m.Called() - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *TelemetryIngressBatchClient) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Ready provides a mock function with given fields: -func (_m *TelemetryIngressBatchClient) Ready() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Send provides a mock function with given fields: _a0 -func (_m *TelemetryIngressBatchClient) Send(_a0 synchronization.TelemPayload) { - _m.Called(_a0) -} - -// Start provides a mock function with given fields: _a0 -func (_m *TelemetryIngressBatchClient) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -type mockConstructorTestingTNewTelemetryIngressBatchClient interface { - mock.TestingT - Cleanup(func()) -} - -// NewTelemetryIngressBatchClient creates a new instance of TelemetryIngressBatchClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTelemetryIngressBatchClient(t mockConstructorTestingTNewTelemetryIngressBatchClient) *TelemetryIngressBatchClient { - mock := &TelemetryIngressBatchClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/synchronization/mocks/telemetry_ingress_client.go b/core/services/synchronization/mocks/telemetry_service.go similarity index 57% rename from core/services/synchronization/mocks/telemetry_ingress_client.go rename to core/services/synchronization/mocks/telemetry_service.go index 42eb4616d0d..bd822666b97 100644 --- a/core/services/synchronization/mocks/telemetry_ingress_client.go +++ b/core/services/synchronization/mocks/telemetry_service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -9,13 +9,13 @@ import ( mock "github.com/stretchr/testify/mock" ) -// TelemetryIngressClient is an autogenerated mock type for the TelemetryIngressClient type -type TelemetryIngressClient struct { +// TelemetryService is an autogenerated mock type for the TelemetryService type +type TelemetryService struct { mock.Mock } // Close provides a mock function with given fields: -func (_m *TelemetryIngressClient) Close() error { +func (_m *TelemetryService) Close() error { ret := _m.Called() var r0 error @@ -29,7 +29,7 @@ func (_m *TelemetryIngressClient) Close() error { } // HealthReport provides a mock function with given fields: -func (_m *TelemetryIngressClient) HealthReport() map[string]error { +func (_m *TelemetryService) HealthReport() map[string]error { ret := _m.Called() var r0 map[string]error @@ -45,7 +45,7 @@ func (_m *TelemetryIngressClient) HealthReport() map[string]error { } // Name provides a mock function with given fields: -func (_m *TelemetryIngressClient) Name() string { +func (_m *TelemetryService) Name() string { ret := _m.Called() var r0 string @@ -59,7 +59,7 @@ func (_m *TelemetryIngressClient) Name() string { } // Ready provides a mock function with given fields: -func (_m *TelemetryIngressClient) Ready() error { +func (_m *TelemetryService) Ready() error { ret := _m.Called() var r0 error @@ -72,13 +72,13 @@ func (_m *TelemetryIngressClient) Ready() error { return r0 } -// Send provides a mock function with given fields: _a0 -func (_m *TelemetryIngressClient) Send(_a0 synchronization.TelemPayload) { - _m.Called(_a0) +// Send provides a mock function with given fields: ctx, telemetry, contractID, telemType +func (_m *TelemetryService) Send(ctx context.Context, telemetry []byte, contractID string, telemType synchronization.TelemetryType) { + _m.Called(ctx, telemetry, contractID, telemType) } // Start provides a mock function with given fields: _a0 -func (_m *TelemetryIngressClient) Start(_a0 context.Context) error { +func (_m *TelemetryService) Start(_a0 context.Context) error { ret := _m.Called(_a0) var r0 error @@ -91,14 +91,13 @@ func (_m *TelemetryIngressClient) Start(_a0 context.Context) error { return r0 } -type mockConstructorTestingTNewTelemetryIngressClient interface { +// NewTelemetryService creates a new instance of TelemetryService. 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 NewTelemetryService(t interface { mock.TestingT Cleanup(func()) -} - -// NewTelemetryIngressClient creates a new instance of TelemetryIngressClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewTelemetryIngressClient(t mockConstructorTestingTNewTelemetryIngressClient) *TelemetryIngressClient { - mock := &TelemetryIngressClient{} +}) *TelemetryService { + mock := &TelemetryService{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index ccafc32bc3d..4924bb2cd50 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -13,21 +13,11 @@ import ( "github.com/smartcontractkit/wsrpc/examples/simple/keys" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -//go:generate mockery --quiet --name TelemetryIngressBatchClient --output ./mocks --case=underscore - -// TelemetryIngressBatchClient encapsulates all the functionality needed to -// send telemetry to the ingress server using wsrpc -type TelemetryIngressBatchClient interface { - services.ServiceCtx - Send(TelemPayload) -} - // NoopTelemetryIngressBatchClient is a no-op interface for TelemetryIngressBatchClient type NoopTelemetryIngressBatchClient struct{} @@ -40,7 +30,6 @@ func (NoopTelemetryIngressBatchClient) Close() error { return nil } // Send is a no-op func (NoopTelemetryIngressBatchClient) Send(TelemPayload) {} -// Healthy is a no-op func (NoopTelemetryIngressBatchClient) HealthReport() map[string]error { return map[string]error{} } func (NoopTelemetryIngressBatchClient) Name() string { return "NoopTelemetryIngressBatchClient" } @@ -77,7 +66,7 @@ type telemetryIngressBatchClient struct { // NewTelemetryIngressBatchClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryIngressBatchClient { +func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryService { return &telemetryIngressBatchClient{ telemBufferSize: telemBufferSize, telemMaxBatchSize: telemMaxBatchSize, @@ -163,7 +152,7 @@ func (tc *telemetryIngressBatchClient) Name() string { } func (tc *telemetryIngressBatchClient) HealthReport() map[string]error { - return map[string]error{tc.Name(): tc.StartStopOnce.Healthy()} + return map[string]error{tc.Name(): tc.Healthy()} } // getCSAPrivateKey gets the client's CSA private key @@ -182,16 +171,22 @@ func (tc *telemetryIngressBatchClient) getCSAPrivateKey() (privkey []byte, err e // Send directs incoming telmetry messages to the worker responsible for pushing it to // the ingress server. If the worker telemetry buffer is full, messages are dropped // and a warning is logged. -func (tc *telemetryIngressBatchClient) Send(payload TelemPayload) { +func (tc *telemetryIngressBatchClient) Send(ctx context.Context, telemData []byte, contractID string, telemType TelemetryType) { if tc.useUniConn && !tc.connected.Load() { tc.lggr.Warnw("not connected to telemetry endpoint", "endpoint", tc.url.String()) return } + payload := TelemPayload{ + Telemetry: telemData, + TelemType: telemType, + ContractID: contractID, + } worker := tc.findOrCreateWorker(payload) + select { case worker.chTelemetry <- payload: worker.dropMessageCount.Store(0) - case <-payload.Ctx.Done(): + case <-ctx.Done(): return default: worker.logBufferFullWithExpBackoff(payload) diff --git a/core/services/synchronization/telemetry_ingress_batch_client_test.go b/core/services/synchronization/telemetry_ingress_batch_client_test.go index 81a3a950f3f..6dd9d401a80 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_client_test.go @@ -41,19 +41,16 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { // Create telemetry payloads for different contracts telemPayload1 := synchronization.TelemPayload{ - Ctx: testutils.Context(t), Telemetry: []byte("Mock telem 1"), ContractID: "0x1", TelemType: synchronization.OCR, } telemPayload2 := synchronization.TelemPayload{ - Ctx: testutils.Context(t), Telemetry: []byte("Mock telem 2"), ContractID: "0x2", TelemType: synchronization.OCR2VRF, } telemPayload3 := synchronization.TelemPayload{ - Ctx: testutils.Context(t), Telemetry: []byte("Mock telem 3"), ContractID: "0x3", TelemType: synchronization.OCR2Functions, @@ -90,13 +87,14 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { }) // Send telemetry - telemIngressClient.Send(telemPayload1) - telemIngressClient.Send(telemPayload2) - telemIngressClient.Send(telemPayload3) + testCtx := testutils.Context(t) + telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) + telemIngressClient.Send(testCtx, telemPayload2.Telemetry, telemPayload2.ContractID, telemPayload2.TelemType) + telemIngressClient.Send(testCtx, telemPayload3.Telemetry, telemPayload3.ContractID, telemPayload3.TelemType) time.Sleep(sendInterval * 2) - telemIngressClient.Send(telemPayload1) - telemIngressClient.Send(telemPayload1) - telemIngressClient.Send(telemPayload2) + telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) + telemIngressClient.Send(testCtx, telemPayload1.Telemetry, telemPayload1.ContractID, telemPayload1.TelemType) + telemIngressClient.Send(testCtx, telemPayload2.Telemetry, telemPayload2.ContractID, telemPayload2.TelemType) // Wait for the telemetry to be handled g.Eventually(func() []uint32 { diff --git a/core/services/synchronization/telemetry_ingress_batch_worker_test.go b/core/services/synchronization/telemetry_ingress_batch_worker_test.go index d81321b1347..109022c7135 100644 --- a/core/services/synchronization/telemetry_ingress_batch_worker_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_worker_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" @@ -15,7 +14,6 @@ import ( func TestTelemetryIngressWorker_BuildTelemBatchReq(t *testing.T) { telemPayload := synchronization.TelemPayload{ - Ctx: testutils.Context(t), Telemetry: []byte("Mock telemetry"), ContractID: "0xa", } diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index d5b0ed7d93b..1db4f69afd8 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -12,23 +12,11 @@ import ( "github.com/smartcontractkit/wsrpc/examples/simple/keys" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" ) -//go:generate mockery --quiet --dir ./telem --name TelemClient --output ./mocks/ --case=underscore - -//go:generate mockery --quiet --name TelemetryIngressClient --output ./mocks --case=underscore - -// TelemetryIngressClient encapsulates all the functionality needed to -// send telemetry to the ingress server using wsrpc -type TelemetryIngressClient interface { - services.ServiceCtx - Send(TelemPayload) -} - type NoopTelemetryIngressClient struct{} // Start is a no-op @@ -38,7 +26,7 @@ func (NoopTelemetryIngressClient) Start(context.Context) error { return nil } func (NoopTelemetryIngressClient) Close() error { return nil } // Send is a no-op -func (NoopTelemetryIngressClient) Send(TelemPayload) {} +func (NoopTelemetryIngressClient) Send(context.Context, TelemPayload) {} func (NoopTelemetryIngressClient) HealthReport() map[string]error { return map[string]error{} } func (NoopTelemetryIngressClient) Name() string { return "NoopTelemetryIngressClient" } @@ -62,16 +50,9 @@ type telemetryIngressClient struct { chTelemetry chan TelemPayload } -type TelemPayload struct { - Ctx context.Context - Telemetry []byte - TelemType TelemetryType - ContractID string -} - // NewTelemetryIngressClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint) TelemetryIngressClient { +func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint) TelemetryService { return &telemetryIngressClient{ url: url, ks: ks, @@ -111,7 +92,7 @@ func (tc *telemetryIngressClient) Name() string { } func (tc *telemetryIngressClient) HealthReport() map[string]error { - return map[string]error{tc.Name(): tc.StartStopOnce.Healthy()} + return map[string]error{tc.Name(): tc.Healthy()} } func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []byte) { @@ -150,6 +131,8 @@ func (tc *telemetryIngressClient) connect(ctx context.Context, clientPrivKey []b func (tc *telemetryIngressClient) handleTelemetry() { go func() { + ctx, cancel := utils.StopChan(tc.chDone).NewCtx() + defer cancel() for { select { case p := <-tc.chTelemetry: @@ -160,7 +143,7 @@ func (tc *telemetryIngressClient) handleTelemetry() { TelemetryType: string(p.TelemType), SentAt: time.Now().UnixNano(), } - _, err := tc.telemClient.Telem(p.Ctx, telemReq) + _, err := tc.telemClient.Telem(ctx, telemReq) if err != nil { tc.lggr.Errorf("Could not send telemetry: %v", err) continue @@ -211,11 +194,17 @@ func (tc *telemetryIngressClient) getCSAPrivateKey() (privkey []byte, err error) // Send sends telemetry to the ingress server using wsrpc if the client is ready. // Also stores telemetry in a small buffer in case of backpressure from wsrpc, // throwing away messages once buffer is full -func (tc *telemetryIngressClient) Send(payload TelemPayload) { +func (tc *telemetryIngressClient) Send(ctx context.Context, telemData []byte, contractID string, telemType TelemetryType) { + payload := TelemPayload{ + Telemetry: telemData, + TelemType: telemType, + ContractID: contractID, + } + select { case tc.chTelemetry <- payload: tc.dropMessageCount.Store(0) - case <-payload.Ctx.Done(): + case <-ctx.Done(): return default: tc.logBufferFullWithExpBackoff(payload) diff --git a/core/services/synchronization/telemetry_ingress_client_test.go b/core/services/synchronization/telemetry_ingress_client_test.go index 83c187baaac..5a0cc23ecd0 100644 --- a/core/services/synchronization/telemetry_ingress_client_test.go +++ b/core/services/synchronization/telemetry_ingress_client_test.go @@ -42,7 +42,6 @@ func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { telemetry := []byte("101010") address := common.HexToAddress("0xa") telemPayload := synchronization.TelemPayload{ - Ctx: testutils.Context(t), Telemetry: telemetry, ContractID: address.String(), TelemType: synchronization.OCR, @@ -60,7 +59,7 @@ func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { }) // Send telemetry - telemIngressClient.Send(telemPayload) + telemIngressClient.Send(testutils.Context(t), telemPayload.Telemetry, telemPayload.ContractID, telemPayload.TelemType) // Wait for the telemetry to be handled gomega.NewWithT(t).Eventually(called.Load).Should(gomega.BeTrue()) diff --git a/core/services/telemetry/common.go b/core/services/telemetry/common.go index cfbd5191304..5a3f6706f7d 100644 --- a/core/services/telemetry/common.go +++ b/core/services/telemetry/common.go @@ -7,5 +7,5 @@ import ( ) type MonitoringEndpointGenerator interface { - GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint + GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint } diff --git a/core/services/telemetry/ingress.go b/core/services/telemetry/ingress.go index a640b4e2a25..637fa0dd3ba 100644 --- a/core/services/telemetry/ingress.go +++ b/core/services/telemetry/ingress.go @@ -11,38 +11,36 @@ import ( var _ MonitoringEndpointGenerator = &IngressAgentWrapper{} type IngressAgentWrapper struct { - telemetryIngressClient synchronization.TelemetryIngressClient + telemetryIngressClient synchronization.TelemetryService } -func NewIngressAgentWrapper(telemetryIngressClient synchronization.TelemetryIngressClient) *IngressAgentWrapper { +func NewIngressAgentWrapper(telemetryIngressClient synchronization.TelemetryService) *IngressAgentWrapper { return &IngressAgentWrapper{telemetryIngressClient} } -func (t *IngressAgentWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { - return NewIngressAgent(t.telemetryIngressClient, contractID, telemType) +func (t *IngressAgentWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { + return NewIngressAgent(t.telemetryIngressClient, contractID, telemType, network, chainID) } type IngressAgent struct { - telemetryIngressClient synchronization.TelemetryIngressClient + telemetryIngressClient synchronization.TelemetryService contractID string telemType synchronization.TelemetryType + network string + chainID string } -func NewIngressAgent(telemetryIngressClient synchronization.TelemetryIngressClient, contractID string, telemType synchronization.TelemetryType) *IngressAgent { +func NewIngressAgent(telemetryIngressClient synchronization.TelemetryService, contractID string, telemType synchronization.TelemetryType, network string, chainID string) *IngressAgent { return &IngressAgent{ telemetryIngressClient, contractID, telemType, + network, + chainID, } } // SendLog sends a telemetry log to the ingress server func (t *IngressAgent) SendLog(telemetry []byte) { - payload := synchronization.TelemPayload{ - Ctx: context.Background(), - Telemetry: telemetry, - ContractID: t.contractID, - TelemType: t.telemType, - } - t.telemetryIngressClient.Send(payload) + t.telemetryIngressClient.Send(context.Background(), telemetry, t.contractID, t.telemType) } diff --git a/core/services/telemetry/ingress_batch.go b/core/services/telemetry/ingress_batch.go index 0cc100e0b87..df860853592 100644 --- a/core/services/telemetry/ingress_batch.go +++ b/core/services/telemetry/ingress_batch.go @@ -12,42 +12,40 @@ var _ MonitoringEndpointGenerator = &IngressAgentBatchWrapper{} // IngressAgentBatchWrapper provides monitoring endpoint generation for the telemetry batch client type IngressAgentBatchWrapper struct { - telemetryIngressBatchClient synchronization.TelemetryIngressBatchClient + telemetryIngressBatchClient synchronization.TelemetryService } // NewIngressAgentBatchWrapper creates a new IngressAgentBatchWrapper with the provided telemetry batch client -func NewIngressAgentBatchWrapper(telemetryIngressBatchClient synchronization.TelemetryIngressBatchClient) *IngressAgentBatchWrapper { +func NewIngressAgentBatchWrapper(telemetryIngressBatchClient synchronization.TelemetryService) *IngressAgentBatchWrapper { return &IngressAgentBatchWrapper{telemetryIngressBatchClient} } // GenMonitoringEndpoint returns a new ingress batch agent instantiated with the batch client and a contractID -func (t *IngressAgentBatchWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { - return NewIngressAgentBatch(t.telemetryIngressBatchClient, contractID, telemType) +func (t *IngressAgentBatchWrapper) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { + return NewIngressAgentBatch(t.telemetryIngressBatchClient, contractID, telemType, network, chainID) } // IngressAgentBatch allows for sending batch telemetry for a given contractID type IngressAgentBatch struct { - telemetryIngressBatchClient synchronization.TelemetryIngressBatchClient + telemetryIngressBatchClient synchronization.TelemetryService contractID string telemType synchronization.TelemetryType + network string + chainID string } // NewIngressAgentBatch creates a new IngressAgentBatch with the given batch client and contractID -func NewIngressAgentBatch(telemetryIngressBatchClient synchronization.TelemetryIngressBatchClient, contractID string, telemType synchronization.TelemetryType) *IngressAgentBatch { +func NewIngressAgentBatch(telemetryIngressBatchClient synchronization.TelemetryService, contractID string, telemType synchronization.TelemetryType, network string, chainID string) *IngressAgentBatch { return &IngressAgentBatch{ telemetryIngressBatchClient, contractID, telemType, + network, + chainID, } } // SendLog sends a telemetry log to the ingress server func (t *IngressAgentBatch) SendLog(telemetry []byte) { - payload := synchronization.TelemPayload{ - Ctx: context.Background(), - Telemetry: telemetry, - ContractID: t.contractID, - TelemType: t.telemType, - } - t.telemetryIngressBatchClient.Send(payload) + t.telemetryIngressBatchClient.Send(context.Background(), telemetry, t.contractID, t.telemType) } diff --git a/core/services/telemetry/ingress_batch_test.go b/core/services/telemetry/ingress_batch_test.go index 70972ecd5a5..3923b569fed 100644 --- a/core/services/telemetry/ingress_batch_test.go +++ b/core/services/telemetry/ingress_batch_test.go @@ -12,14 +12,18 @@ import ( ) func TestIngressAgentBatch(t *testing.T) { - telemetryBatchClient := mocks.NewTelemetryIngressBatchClient(t) + telemetryBatchClient := mocks.NewTelemetryService(t) ingressAgentBatch := telemetry.NewIngressAgentWrapper(telemetryBatchClient) - monitoringEndpoint := ingressAgentBatch.GenMonitoringEndpoint("0xa", synchronization.OCR) + monitoringEndpoint := ingressAgentBatch.GenMonitoringEndpoint("0xa", synchronization.OCR, "test-network", "test-chainID") // Handle the Send call and store the telem var telemPayload synchronization.TelemPayload - telemetryBatchClient.On("Send", mock.AnythingOfType("synchronization.TelemPayload")).Return().Run(func(args mock.Arguments) { - telemPayload = args[0].(synchronization.TelemPayload) + telemetryBatchClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + telemPayload = synchronization.TelemPayload{ + Telemetry: args[1].([]byte), + ContractID: args[2].(string), + TelemType: args[3].(synchronization.TelemetryType), + } }) // Send the log to the monitoring endpoint diff --git a/core/services/telemetry/ingress_test.go b/core/services/telemetry/ingress_test.go index 7531a567982..31028f2f605 100644 --- a/core/services/telemetry/ingress_test.go +++ b/core/services/telemetry/ingress_test.go @@ -12,14 +12,18 @@ import ( ) func TestIngressAgent(t *testing.T) { - telemetryClient := mocks.NewTelemetryIngressClient(t) + telemetryClient := mocks.NewTelemetryService(t) ingressAgent := telemetry.NewIngressAgentWrapper(telemetryClient) - monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.OCR) + monitoringEndpoint := ingressAgent.GenMonitoringEndpoint("0xa", synchronization.OCR, "test-network", "test-chainID") // Handle the Send call and store the telem var telemPayload synchronization.TelemPayload - telemetryClient.On("Send", mock.AnythingOfType("synchronization.TelemPayload")).Return().Run(func(args mock.Arguments) { - telemPayload = args[0].(synchronization.TelemPayload) + telemetryClient.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + telemPayload = synchronization.TelemPayload{ + Telemetry: args[1].([]byte), + ContractID: args[2].(string), + TelemType: args[3].(synchronization.TelemetryType), + } }) // Send the log to the monitoring endpoint diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go new file mode 100644 index 00000000000..3818341f5b1 --- /dev/null +++ b/core/services/telemetry/manager.go @@ -0,0 +1,221 @@ +package telemetry + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/commontypes" + "go.uber.org/multierr" + + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +//// Client encapsulates all the functionality needed to +//// send telemetry to the ingress server using wsrpc +//type Client interface { +// services.ServiceCtx +// Send(context.Context, synchronization.TelemPayload) +//} + +type Manager struct { + utils.StartStopOnce + bufferSize uint + endpoints []*telemetryEndpoint + ks keystore.CSA + lggr logger.Logger + logging bool + maxBatchSize uint + sendInterval time.Duration + sendTimeout time.Duration + uniConn bool + useBatchSend bool + MonitoringEndpointGenerator MonitoringEndpointGenerator + + //legacyMode means that we are sending all telemetry to a single endpoint. + //In order for this to be set as true, we need to have no endpoints defined with TelemetryIngress.URL and TelemetryIngress.ServerPubKey set. + //This mode will be supported until we completely switch to TelemetryIngress.Endpoints in config.toml + legacyMode bool +} + +type legacyEndpointConfig struct { + Url *url.URL + PubKey string +} + +func (l *legacyEndpointConfig) Network() string { + return "-" +} + +func (l *legacyEndpointConfig) ChainID() string { + return "-" +} + +func (l *legacyEndpointConfig) ServerPubKey() string { + return l.PubKey +} + +func (l *legacyEndpointConfig) URL() *url.URL { + return l.Url +} + +type telemetryEndpoint struct { + utils.StartStopOnce + ChainID string + Network string + URL *url.URL + client synchronization.TelemetryService + PubKey string +} + +// NewManager create a new telemetry manager that is responsible for configuring telemetry agents and generating the defined telemetry endpoints and monitoring endpoints +func NewManager(cfg config.TelemetryIngress, csaKeyStore keystore.CSA, lggr logger.Logger) *Manager { + m := &Manager{ + bufferSize: cfg.BufferSize(), + endpoints: nil, + ks: csaKeyStore, + lggr: lggr.Named("TelemetryManager"), + logging: cfg.Logging(), + maxBatchSize: cfg.MaxBatchSize(), + sendInterval: cfg.SendInterval(), + sendTimeout: cfg.SendTimeout(), + uniConn: cfg.UniConn(), + useBatchSend: cfg.UseBatchSend(), + legacyMode: false, + } + for _, e := range cfg.Endpoints() { + if err := m.addEndpoint(e); err != nil { + m.lggr.Error(err) + } + } + + if len(cfg.Endpoints()) == 0 && cfg.URL() != nil && cfg.ServerPubKey() != "" { + m.lggr.Error(`TelemetryIngress.URL and TelemetryIngress.ServerPubKey will be removed in a future version, please switch to TelemetryIngress.Endpoints: + [[TelemetryIngress.Endpoints]] + Network = '...' # e.g. EVM. Solana, Starknet, Cosmos + ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta + URL = '...' + ServerPubKey = '...'`) + m.legacyMode = true + if err := m.addEndpoint(&legacyEndpointConfig{ + Url: cfg.URL(), + PubKey: cfg.ServerPubKey(), + }); err != nil { + m.lggr.Error(err) + } + } + + return m +} + +func (m *Manager) Start(ctx context.Context) error { + return m.StartOnce("TelemetryManager", func() error { + var err error + for _, e := range m.endpoints { + err = multierr.Append(err, e.client.Start(ctx)) + } + return err + }) +} +func (m *Manager) Close() error { + return m.StopOnce("TelemetryManager", func() error { + var err error + for _, e := range m.endpoints { + err = multierr.Append(err, e.client.Close()) + } + return err + }) +} + +func (m *Manager) Name() string { + return m.lggr.Name() +} + +func (m *Manager) HealthReport() map[string]error { + hr := make(map[string]error) + hr[m.lggr.Name()] = m.Healthy() + for _, e := range m.endpoints { + name := fmt.Sprintf("%s.%s.%s", m.lggr.Name(), e.Network, e.ChainID) + hr[name] = e.StartStopOnce.Healthy() + } + return hr +} + +// GenMonitoringEndpoint creates a new monitoring endpoints based on the existing available endpoints defined in the core config TOML, if no endpoint for the network and chainID exists, a NOOP agent will be used and the telemetry will not be sent +func (m *Manager) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) commontypes.MonitoringEndpoint { + + e, found := m.getEndpoint(network, chainID) + + if !found { + m.lggr.Warnf("no telemetry endpoint found for network %q chainID %q, telemetry %q for contactID %q will NOT be sent", network, chainID, telemType, contractID) + return &NoopAgent{} + } + + if m.useBatchSend { + return NewIngressAgentBatch(e.client, contractID, telemType, network, chainID) + } + + return NewIngressAgent(e.client, contractID, telemType, network, chainID) + +} + +func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { + if e.Network() == "" && !m.legacyMode { + return errors.New("cannot add telemetry endpoint, network cannot be empty") + } + + if e.ChainID() == "" && !m.legacyMode { + return errors.New("cannot add telemetry endpoint, chainID cannot be empty") + } + + if e.URL() == nil { + return errors.New("cannot add telemetry endpoint, URL cannot be empty") + } + + if e.ServerPubKey() == "" { + return errors.New("cannot add telemetry endpoint, ServerPubKey cannot be empty") + } + + if _, found := m.getEndpoint(e.Network(), e.ChainID()); found { + return errors.Errorf("cannot add telemetry endpoint for network %q and chainID %q, endpoint already exists", e.Network(), e.ChainID()) + } + + var tClient synchronization.TelemetryService + if m.useBatchSend { + tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, m.maxBatchSize, m.sendInterval, m.sendTimeout, m.uniConn) + } else { + tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize) + } + + te := telemetryEndpoint{ + Network: strings.ToUpper(e.Network()), + ChainID: strings.ToUpper(e.ChainID()), + URL: e.URL(), + PubKey: e.ServerPubKey(), + client: tClient, + } + + m.endpoints = append(m.endpoints, &te) + return nil +} + +func (m *Manager) getEndpoint(network string, chainID string) (*telemetryEndpoint, bool) { + //in legacy mode we send telemetry to a single endpoint + if m.legacyMode && len(m.endpoints) == 1 { + return m.endpoints[0], true + } + + for _, e := range m.endpoints { + if e.Network == strings.ToUpper(network) && e.ChainID == strings.ToUpper(chainID) { + return e, true + } + } + return nil, false +} diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go new file mode 100644 index 00000000000..4aaf3280155 --- /dev/null +++ b/core/services/telemetry/manager_test.go @@ -0,0 +1,341 @@ +package telemetry + +import ( + "context" + "fmt" + "math/big" + "net/url" + "reflect" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/config/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" + mocks3 "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" + mocks2 "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +func setupMockConfig(t *testing.T, useBatchSend bool) *mocks.TelemetryIngress { + tic := mocks.NewTelemetryIngress(t) + tic.On("BufferSize").Return(uint(123)) + tic.On("Logging").Return(true) + tic.On("MaxBatchSize").Return(uint(51)) + tic.On("SendInterval").Return(time.Millisecond * 512) + tic.On("SendTimeout").Return(time.Second * 7) + tic.On("UniConn").Return(true) + tic.On("UseBatchSend").Return(useBatchSend) + + return tic +} + +func TestManagerAgents(t *testing.T) { + tic := setupMockConfig(t, true) + te := mocks.NewTelemetryIngressEndpoint(t) + te.On("Network").Return("network-1") + te.On("ChainID").Return("network-1-chainID-1") + te.On("ServerPubKey").Return("some-pubkey") + u, _ := url.Parse("http://some-url.test") + te.On("URL").Return(u) + tic.On("Endpoints").Return([]config.TelemetryIngressEndpoint{te}) + + lggr, _ := logger.TestLoggerObserved(t, zapcore.InfoLevel) + + ks := mocks3.NewCSA(t) + + tm := NewManager(tic, ks, lggr) + require.Equal(t, "*synchronization.telemetryIngressBatchClient", reflect.TypeOf(tm.endpoints[0].client).String()) + me := tm.GenMonitoringEndpoint("", "", "network-1", "network-1-chainID-1") + require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(me).String()) + + tic = setupMockConfig(t, false) + tic.On("Endpoints").Return([]config.TelemetryIngressEndpoint{te}) + tm = NewManager(tic, ks, lggr) + require.Equal(t, "*synchronization.telemetryIngressClient", reflect.TypeOf(tm.endpoints[0].client).String()) + me = tm.GenMonitoringEndpoint("", "", "network-1", "network-1-chainID-1") + require.Equal(t, "*telemetry.IngressAgent", reflect.TypeOf(me).String()) +} + +func TestNewManager(t *testing.T) { + + type endpointTest struct { + network string + chainID string + url string + pubKey string + shouldError bool + expectedError string + } + + endpoints := []endpointTest{ + { + network: "NETWORK-1", + chainID: "NETWORK-1-CHAINID-1", + url: "http://network-1-chainID-1.test", + pubKey: "network-1-chainID-1-pub-key", + shouldError: false, + }, + { + network: "NETWORK-1", + chainID: "NETWORK-1-CHAINID-2", + url: "http://network-1-chainID-2.test", + pubKey: "network-1-chainID-2-pub-key", + shouldError: false, + }, + { + network: "NETWORK-2", + chainID: "NETWORK-2-CHAINID-1", + url: "http://network-2-chainID-1.test", + pubKey: "network-2-chainID-1-pub-key", + shouldError: false, + }, + { + shouldError: true, + expectedError: "network cannot be empty", + }, + { + network: "ERROR", + shouldError: true, + expectedError: "chainID cannot be empty", + }, + { + network: "ERROR", + chainID: "ERROR", + shouldError: true, + expectedError: "URL cannot be empty", + }, + { + network: "ERROR", + chainID: "ERROR", + url: "http://error.test", + shouldError: true, + expectedError: "cannot add telemetry endpoint, ServerPubKey cannot be empty", + }, + { + network: "NETWORK-1", + chainID: "NETWORK-1-CHAINID-1", + url: "http://network-1-chainID-1.test", + pubKey: "network-1-chainID-1-pub-key", + shouldError: true, + expectedError: "endpoint already exists", + }, + } + + var mockEndpoints []config.TelemetryIngressEndpoint + + for _, e := range endpoints { + te := mocks.NewTelemetryIngressEndpoint(t) + te.On("Network").Maybe().Return(e.network) + te.On("ChainID").Maybe().Return(e.chainID) + te.On("ServerPubKey").Maybe().Return(e.pubKey) + + u, _ := url.Parse(e.url) + if e.url == "" { + u = nil + } + te.On("URL").Maybe().Return(u) + mockEndpoints = append(mockEndpoints, te) + } + + tic := setupMockConfig(t, true) + tic.On("Endpoints").Return(mockEndpoints) + + lggr, logObs := logger.TestLoggerObserved(t, zapcore.InfoLevel) + + ks := mocks3.NewCSA(t) + + ks.On("GetAll").Return([]csakey.KeyV2{csakey.MustNewV2XXXTestingOnly(big.NewInt(0))}, nil) + + m := NewManager(tic, ks, lggr) + + require.Equal(t, uint(123), m.bufferSize) + require.Equal(t, ks, m.ks) + require.Equal(t, "TelemetryManager", m.lggr.Name()) + require.Equal(t, true, m.logging) + require.Equal(t, uint(51), m.maxBatchSize) + require.Equal(t, time.Millisecond*512, m.sendInterval) + require.Equal(t, time.Second*7, m.sendTimeout) + require.Equal(t, true, m.uniConn) + require.Equal(t, true, m.useBatchSend) + + logs := logObs.TakeAll() + for i, e := range endpoints { + if !e.shouldError { + require.Equal(t, e.network, m.endpoints[i].Network) + require.Equal(t, e.chainID, m.endpoints[i].ChainID) + require.Equal(t, e.pubKey, m.endpoints[i].PubKey) + require.Equal(t, e.url, m.endpoints[i].URL.String()) + } else { + found := false + for _, l := range logs { + if strings.Contains(l.Message, e.expectedError) { + found = true + } + } + require.Equal(t, true, found, "cannot find log: %s", e.expectedError) + } + + } + + require.Equal(t, "TelemetryManager", m.Name()) + + require.Nil(t, m.Start(context.Background())) + testutils.WaitForLogMessageCount(t, logObs, "error connecting error while dialing dial tcp", 3) + + hr := m.HealthReport() + require.Equal(t, 4, len(hr)) + require.Nil(t, m.Close()) + time.Sleep(time.Second * 1) +} + +func TestCorrectEndpointRouting(t *testing.T) { + tic := setupMockConfig(t, true) + tic.On("Endpoints").Return(nil) + tic.On("URL").Return(nil) + + lggr, obsLogs := logger.TestLoggerObserved(t, zapcore.InfoLevel) + ks := mocks3.NewCSA(t) + + tm := NewManager(tic, ks, lggr) + + type testEndpoint struct { + network string + chainID string + } + + testEndpoints := []testEndpoint{ + { + network: "NETWORK-1", + chainID: "NETWORK-1-CHAINID-1", + }, + { + network: "NETWORK-1", + chainID: "NETWORK-1-CHAINID-2", + }, + { + network: "NETWORK-2", + chainID: "NETWORK-2-CHAINID-1", + }, + { + network: "NETWORK-2", + chainID: "NETWORK-2-CHAINID-2", + }, + } + + tm.endpoints = make([]*telemetryEndpoint, len(testEndpoints)) + clientSent := make([]synchronization.TelemPayload, 0) + for i, e := range testEndpoints { + clientMock := mocks2.NewTelemetryService(t) + clientMock.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + clientSent = append(clientSent, synchronization.TelemPayload{ + Telemetry: args[1].([]byte), + ContractID: args[2].(string), + TelemType: args[3].(synchronization.TelemetryType), + }) + }) + + tm.endpoints[i] = &telemetryEndpoint{ + StartStopOnce: utils.StartStopOnce{}, + ChainID: e.chainID, + Network: e.network, + client: clientMock, + } + + } + //Unknown networks or chainID + noopEndpoint := tm.GenMonitoringEndpoint("some-contractID", "some-type", "unknown-network", "unknown-chainID") + require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) + require.Equal(t, 1, obsLogs.Len()) + require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") + + noopEndpoint = tm.GenMonitoringEndpoint("some-contractID", "some-type", "network-1", "unknown-chainID") + require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) + require.Equal(t, 1, obsLogs.Len()) + require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") + + noopEndpoint = tm.GenMonitoringEndpoint("some-contractID", "some-type", "network-2", "network-1-chainID-1") + require.Equal(t, "*telemetry.NoopAgent", reflect.TypeOf(noopEndpoint).String()) + require.Equal(t, 1, obsLogs.Len()) + require.Contains(t, obsLogs.TakeAll()[0].Message, "no telemetry endpoint found") + + //Known networks and chainID + for i, e := range testEndpoints { + telemType := fmt.Sprintf("TelemType_%s", e.chainID) + contractID := fmt.Sprintf("contractID_%s", e.chainID) + me := tm.GenMonitoringEndpoint( + contractID, + synchronization.TelemetryType(telemType), + e.network, + e.chainID, + ) + me.SendLog([]byte(e.chainID)) + require.Equal(t, 0, obsLogs.Len()) + + require.Equal(t, i+1, len(clientSent)) + require.Equal(t, contractID, clientSent[i].ContractID) + require.Equal(t, telemType, string(clientSent[i].TelemType)) + require.Equal(t, []byte(e.chainID), clientSent[i].Telemetry) + } + +} + +func TestLegacyMode(t *testing.T) { + tic := setupMockConfig(t, true) + tic.On("Endpoints").Return(nil) + url, err := models.ParseURL("test.test") + require.NoError(t, err) + tic.On("URL").Return(url.URL()) + tic.On("ServerPubKey").Return("some-pub-key") + + lggr, obsLogs := logger.TestLoggerObserved(t, zapcore.InfoLevel) + ks := mocks3.NewCSA(t) + + tm := NewManager(tic, ks, lggr) + require.Equal(t, true, tm.legacyMode) + require.Len(t, tm.endpoints, 1) + + var clientSent []synchronization.TelemPayload + clientMock := mocks2.NewTelemetryService(t) + clientMock.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { + clientSent = append(clientSent, synchronization.TelemPayload{ + Telemetry: args[1].([]byte), + ContractID: args[2].(string), + TelemType: args[3].(synchronization.TelemetryType), + }) + }) + tm.endpoints[0].client = clientMock + + e := tm.GenMonitoringEndpoint("some-contractID", "some-type", "unknown-network", "unknown-chainID") + require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) + + e.SendLog([]byte("endpoint-1-message-1")) + e.SendLog([]byte("endpoint-1-message-2")) + e.SendLog([]byte("endpoint-1-message-3")) + require.Len(t, clientSent, 3) + + e2 := tm.GenMonitoringEndpoint("another-contractID", "another-type", "another-unknown-network", "another-unknown-chainID") + require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) + + e2.SendLog([]byte("endpoint-2-message-1")) + e2.SendLog([]byte("endpoint-2-message-2")) + e2.SendLog([]byte("endpoint-2-message-3")) + require.Len(t, clientSent, 6) + assert.Equal(t, []byte("endpoint-1-message-1"), clientSent[0].Telemetry) + assert.Equal(t, []byte("endpoint-1-message-2"), clientSent[1].Telemetry) + assert.Equal(t, []byte("endpoint-1-message-3"), clientSent[2].Telemetry) + assert.Equal(t, []byte("endpoint-2-message-1"), clientSent[3].Telemetry) + assert.Equal(t, []byte("endpoint-2-message-2"), clientSent[4].Telemetry) + assert.Equal(t, []byte("endpoint-2-message-3"), clientSent[5].Telemetry) + assert.Equal(t, 1, obsLogs.Len()) // Deprecation warning for TelemetryIngress.URL and TelemetryIngress.ServerPubKey +} diff --git a/core/services/telemetry/noop.go b/core/services/telemetry/noop.go index 71670f2a198..cbeb0387089 100644 --- a/core/services/telemetry/noop.go +++ b/core/services/telemetry/noop.go @@ -16,6 +16,6 @@ func (t *NoopAgent) SendLog(log []byte) { } // GenMonitoringEndpoint creates a monitoring endpoint for telemetry -func (t *NoopAgent) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { +func (t *NoopAgent) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType, network string, chainID string) ocrtypes.MonitoringEndpoint { return t } diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index b5fe6cda76f..f6b6a460b89 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -5,7 +5,9 @@ import ( "fmt" "math/big" "strings" + "time" + "github.com/avast/retry-go/v4" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/theodesp/go-heaps/pairing" @@ -58,7 +60,7 @@ func NewDelegate( pr: pr, porm: porm, legacyChains: legacyChains, - lggr: lggr, + lggr: lggr.Named("VRF"), mailMon: mailMon, } } @@ -73,7 +75,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) {} func (d *Delegate) OnDeleteJob(spec job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if jb.VRFSpec == nil || jb.PipelineSpec == nil { return nil, errors.Errorf("vrf.Delegate expects a VRFSpec and PipelineSpec to be present, got %+v", jb) } @@ -119,7 +121,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC } } - l := d.lggr.With( + l := d.lggr.Named(jb.ExternalJobID.String()).With( "jobID", jb.ID, "externalJobID", jb.ExternalJobID, "coordinatorAddress", jb.VRFSpec.CoordinatorAddress, @@ -130,27 +132,36 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC for _, task := range pl.Tasks { if _, ok := task.(*pipeline.VRFTaskV2Plus); ok { - if err := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { - return nil, err + if err2 := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { + return nil, err2 } if !FromAddressMaxGasPricesAllEqual(jb, chain.Config().EVM().GasEstimator().PriceMaxKey) { return nil, errors.New("key-specific max gas prices of all fromAddresses are not equal, please set them to equal values") } - if err := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().GasEstimator().PriceMaxKey); err != nil { - return nil, err + if err2 := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().GasEstimator().PriceMaxKey); err != nil { + return nil, err2 } if vrfOwner != nil { return nil, errors.New("VRF Owner is not supported for VRF V2 Plus") } - linkNativeFeedAddress, err := coordinatorV2Plus.LINKNATIVEFEED(nil) + + // Get the LINKNATIVEFEED address with retries + // This is needed because the RPC endpoint may be down so we need to + // switch over to another one. + var linkNativeFeedAddress common.Address + err = retry.Do(func() error { + linkNativeFeedAddress, err = coordinatorV2Plus.LINKNATIVEFEED(nil) + return err + }, retry.Attempts(10), retry.Delay(500*time.Millisecond)) if err != nil { - return nil, errors.Wrap(err, "LINKNATIVEFEED") + return nil, errors.Wrap(err, "can't call LINKNATIVEFEED") } - aggregator, err := aggregator_v3_interface.NewAggregatorV3Interface(linkNativeFeedAddress, chain.Client()) - if err != nil { - return nil, errors.Wrap(err, "NewAggregatorV3Interface") + + aggregator, err2 := aggregator_v3_interface.NewAggregatorV3Interface(linkNativeFeedAddress, chain.Client()) + if err2 != nil { + return nil, errors.Wrap(err2, "NewAggregatorV3Interface") } return []job.ServiceCtx{v2.New( @@ -177,19 +188,26 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC vrfcommon.NewLogDeduper(int(chain.Config().EVM().FinalityDepth())))}, nil } if _, ok := task.(*pipeline.VRFTaskV2); ok { - if err := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { - return nil, err + if err2 := CheckFromAddressesExist(jb, d.ks.Eth()); err != nil { + return nil, err2 } if !FromAddressMaxGasPricesAllEqual(jb, chain.Config().EVM().GasEstimator().PriceMaxKey) { return nil, errors.New("key-specific max gas prices of all fromAddresses are not equal, please set them to equal values") } - if err := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().GasEstimator().PriceMaxKey); err != nil { - return nil, err + if err2 := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().GasEstimator().PriceMaxKey); err != nil { + return nil, err2 } - linkEthFeedAddress, err := coordinatorV2.LINKETHFEED(nil) + // Get the LINKETHFEED address with retries + // This is needed because the RPC endpoint may be down so we need to + // switch over to another one. + var linkEthFeedAddress common.Address + err = retry.Do(func() error { + linkEthFeedAddress, err = coordinatorV2.LINKETHFEED(nil) + return err + }, retry.Attempts(10), retry.Delay(500*time.Millisecond)) if err != nil { return nil, errors.Wrap(err, "LINKETHFEED") } diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index ae0accc329e..8c522520faf 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -77,7 +77,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv prm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) txm := txmmocks.NewMockEvmTxManager(t) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{LogBroadcaster: lb, KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jrm := job.NewORM(db, legacyChains, prm, btORM, ks, lggr, cfg.Database()) @@ -116,11 +116,11 @@ func generateCallbackReturnValues(t *testing.T, fulfilled bool) []byte { var args abi.Arguments = []abi.Argument{{Type: callback}} if fulfilled { // Empty callback - b, err := args.Pack(solidity_vrf_coordinator_interface.Callbacks{ + b, err2 := args.Pack(solidity_vrf_coordinator_interface.Callbacks{ RandomnessFee: big.NewInt(10), SeedAndBlockNum: utils.EmptyHash, }) - require.NoError(t, err) + require.NoError(t, err2) return b } b, err := args.Pack(solidity_vrf_coordinator_interface.Callbacks{ @@ -305,6 +305,7 @@ func TestDelegate_ValidLog(t *testing.T) { // Ensure we queue up a valid eth transaction // Linked to requestID vuni.txm.On("CreateTransaction", + mock.Anything, mock.MatchedBy(func(txRequest txmgr.TxRequest) bool { meta := txRequest.Meta return txRequest.FromAddress == vuni.submitter && @@ -564,7 +565,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) require.NoError(t, ks.Unlock(testutils.Password)) var fromAddresses []string @@ -592,7 +593,7 @@ func Test_CheckFromAddressesExist(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewTestGeneralConfig(t) lggr := logger.TestLogger(t) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) require.NoError(t, ks.Unlock(testutils.Password)) var fromAddresses []string diff --git a/core/services/vrf/mocks/aggregator_v3_interface.go b/core/services/vrf/mocks/aggregator_v3_interface.go index 825edebb5a8..956e315f297 100644 --- a/core/services/vrf/mocks/aggregator_v3_interface.go +++ b/core/services/vrf/mocks/aggregator_v3_interface.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -157,13 +157,12 @@ func (_m *AggregatorV3Interface) Version(opts *bind.CallOpts) (*big.Int, error) return r0, r1 } -type mockConstructorTestingTNewAggregatorV3Interface interface { +// NewAggregatorV3Interface creates a new instance of AggregatorV3Interface. 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 NewAggregatorV3Interface(t interface { mock.TestingT Cleanup(func()) -} - -// NewAggregatorV3Interface creates a new instance of AggregatorV3Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewAggregatorV3Interface(t mockConstructorTestingTNewAggregatorV3Interface) *AggregatorV3Interface { +}) *AggregatorV3Interface { mock := &AggregatorV3Interface{} mock.Mock.Test(t) diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index 574d448b94e..72d5960f2c9 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -37,13 +37,12 @@ func (_m *Config) MinIncomingConfirmations() uint32 { return r0 } -type mockConstructorTestingTNewConfig interface { +// NewConfig creates a new instance of Config. 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 NewConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { +}) *Config { mock := &Config{} mock.Mock.Test(t) diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index bcf0bfce381..55a6360c339 100644 --- a/core/services/vrf/mocks/fee_config.go +++ b/core/services/vrf/mocks/fee_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -62,13 +62,12 @@ func (_m *FeeConfig) PriceMaxKey(addr common.Address) *assets.Wei { return r0 } -type mockConstructorTestingTNewFeeConfig interface { +// NewFeeConfig creates a new instance of FeeConfig. 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 NewFeeConfig(t interface { mock.TestingT Cleanup(func()) -} - -// NewFeeConfig creates a new instance of FeeConfig. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewFeeConfig(t mockConstructorTestingTNewFeeConfig) *FeeConfig { +}) *FeeConfig { mock := &FeeConfig{} mock.Mock.Test(t) diff --git a/core/services/vrf/mocks/vrf_coordinator_v2.go b/core/services/vrf/mocks/vrf_coordinator_v2.go index 4bb8ca6f993..c39995b38e9 100644 --- a/core/services/vrf/mocks/vrf_coordinator_v2.go +++ b/core/services/vrf/mocks/vrf_coordinator_v2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -2166,13 +2166,12 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferred(opts *bin return r0, r1 } -type mockConstructorTestingTNewVRFCoordinatorV2Interface interface { +// NewVRFCoordinatorV2Interface creates a new instance of VRFCoordinatorV2Interface. 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 NewVRFCoordinatorV2Interface(t interface { mock.TestingT Cleanup(func()) -} - -// NewVRFCoordinatorV2Interface creates a new instance of VRFCoordinatorV2Interface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewVRFCoordinatorV2Interface(t mockConstructorTestingTNewVRFCoordinatorV2Interface) *VRFCoordinatorV2Interface { +}) *VRFCoordinatorV2Interface { mock := &VRFCoordinatorV2Interface{} mock.Mock.Test(t) diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_abi_values.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_abi_values.go index f3b900d2efc..e5573deffbc 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_abi_values.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_abi_values.go @@ -38,16 +38,8 @@ type abiValues struct { randomnessRequestRawDataArgs abi.Arguments } -var dontUseThisUseGetterFunctionsAbove abiValues -var parseABIOnce sync.Once - -func coordinatorABIValues() *abiValues { - parseABIOnce.Do(readCoordinatorABI) - return &dontUseThisUseGetterFunctionsAbove -} - -func readCoordinatorABI() { - v := &dontUseThisUseGetterFunctionsAbove +var coordinatorABIValues = sync.OnceValue(func() (v *abiValues) { + v = new(abiValues) var err error v.coordinatorABI, err = abi.JSON(strings.NewReader( solidity_vrf_coordinator_interface.VRFCoordinatorABI)) @@ -57,8 +49,7 @@ func readCoordinatorABI() { var found bool v.fulfillMethod, found = v.coordinatorABI.Methods[fulfillMethodName] if !found { - panic(fmt.Errorf("could not find method %s in VRFCoordinator ABI", - fulfillMethodName)) + panic(fmt.Errorf("could not find method %s in VRFCoordinator ABI", fulfillMethodName)) } v.fulfillSelector = hexutil.Encode(v.fulfillMethod.ID) randomnessRequestABI := v.coordinatorABI.Events["RandomnessRequest"] @@ -68,4 +59,5 @@ func readCoordinatorABI() { v.randomnessRequestRawDataArgs = append(v.randomnessRequestRawDataArgs, arg) } } -} + return +}) diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index 14cbb36c9d6..b7e6be43183 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -98,7 +98,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { // Ensure the eth transaction gets confirmed on chain. gomega.NewWithT(t).Eventually(func() bool { orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) - uc, err2 := orm.CountUnconfirmedTransactions(key1.Address, testutils.SimulatedChainID) + uc, err2 := orm.CountUnconfirmedTransactions(testutils.Context(t), key1.Address, testutils.SimulatedChainID) require.NoError(t, err2) return uc == 0 }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.BeTrue()) @@ -106,8 +106,8 @@ func TestIntegration_VRF_JPV2(t *testing.T) { // Assert the request was fulfilled on-chain. var rf []*solidity_vrf_coordinator_interface.VRFCoordinatorRandomnessRequestFulfilled gomega.NewWithT(t).Eventually(func() bool { - rfIterator, err := cu.RootContract.FilterRandomnessRequestFulfilled(nil) - require.NoError(t, err, "failed to subscribe to RandomnessRequest logs") + rfIterator, err2 := cu.RootContract.FilterRandomnessRequestFulfilled(nil) + require.NoError(t, err2, "failed to subscribe to RandomnessRequest logs") rf = nil for rfIterator.Next() { rf = append(rf, rfIterator.Event) @@ -150,7 +150,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { // Create BHS Job and start it bhsJob := vrftesthelpers.CreateAndStartBHSJob(t, sendingKeys, app, cu.BHSContractAddress.String(), - cu.RootContractAddress.String(), "", "", "", 0, 200, 0) + cu.RootContractAddress.String(), "", "", "", 0, 200, 0, 100) // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) @@ -172,20 +172,19 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { // Wait for the blockhash to be stored gomega.NewGomegaWithT(t).Eventually(func() bool { cu.Backend.Commit() - _, err := cu.BHSContract.GetBlockhash(&bind.CallOpts{ + _, err2 := cu.BHSContract.GetBlockhash(&bind.CallOpts{ Pending: false, From: common.Address{}, BlockNumber: nil, Context: nil, }, requestBlock) - if err == nil { + if err2 == nil { return true - } else if strings.Contains(err.Error(), "execution reverted") { - return false - } else { - t.Fatal(err) + } else if strings.Contains(err2.Error(), "execution reverted") { return false } + t.Fatal(err2) + return false }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) // Wait another 160 blocks so that the request is outside the 256 block window @@ -215,7 +214,7 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { // Ensure the eth transaction gets confirmed on chain. gomega.NewWithT(t).Eventually(func() bool { orm := txmgr.NewTxStore(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) - uc, err2 := orm.CountUnconfirmedTransactions(key.Address, testutils.SimulatedChainID) + uc, err2 := orm.CountUnconfirmedTransactions(testutils.Context(t), key.Address, testutils.SimulatedChainID) require.NoError(t, err2) return uc == 0 }, 5*time.Second, 100*time.Millisecond).Should(gomega.BeTrue()) diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index b843dbca9eb..0da28378d01 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -82,7 +82,7 @@ func TestStartHeartbeats(t *testing.T) { _ = vrftesthelpers.CreateAndStartBHSJob( t, bhsKeyAddresses, app, uni.bhsContractAddress.String(), "", - v2CoordinatorAddress, v2PlusCoordinatorAddress, "", 0, 200, heartbeatPeriod) + v2CoordinatorAddress, v2PlusCoordinatorAddress, "", 0, 200, heartbeatPeriod, 100) // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 81f3edfbb2e..09c9a0ed437 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -241,7 +241,7 @@ func testMultipleConsumersNeedBHS( _ = vrftesthelpers.CreateAndStartBHSJob( t, bhsKeyAddresses, app, uni.bhsContractAddress.String(), "", - v2CoordinatorAddress, v2PlusCoordinatorAddress, "", 0, 200, 0) + v2CoordinatorAddress, v2PlusCoordinatorAddress, "", 0, 200, 0, 100) // Ensure log poller is ready and has all logs. require.NoError(t, app.GetRelayers().LegacyEVMChains().Slice()[0].LogPoller().Ready()) @@ -343,13 +343,16 @@ func testMultipleConsumersNeedTrustedBHS( }) // Whitelist vrf key for trusted BHS. - _, err := uni.trustedBhsContract.SetWhitelist(uni.neil, bhsKeyAddresses) - require.NoError(t, err) - uni.backend.Commit() + { + _, err := uni.trustedBhsContract.SetWhitelist(uni.neil, bhsKeyAddresses) + require.NoError(t, err) + uni.backend.Commit() + } config, db := heavyweight.FullTestDBV2(t, "vrfv2_needs_trusted_blockhash_store", func(c *chainlink.Config, s *chainlink.Secrets) { simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) + c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(5_000_000)) c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) @@ -384,9 +387,13 @@ func testMultipleConsumersNeedTrustedBHS( v2PlusCoordinatorAddress = coordinatorAddress.String() } + waitBlocks := 100 + if addedDelay { + waitBlocks = 400 + } _ = vrftesthelpers.CreateAndStartBHSJob( t, bhsKeyAddressesStrings, app, "", "", - v2CoordinatorAddress, v2PlusCoordinatorAddress, uni.trustedBhsContractAddress.String(), 20, 1000, 0) + v2CoordinatorAddress, v2PlusCoordinatorAddress, uni.trustedBhsContractAddress.String(), 20, 1000, 0, waitBlocks) // Ensure log poller is ready and has all logs. chain := app.GetRelayers().LegacyEVMChains().Slice()[0] @@ -470,10 +477,9 @@ func verifyBlockhashStored( return true } else if strings.Contains(err.Error(), "execution reverted") { return false - } else { - t.Fatal(err) - return false } + t.Fatal(err) + return false }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } @@ -496,10 +502,9 @@ func verifyBlockhashStoredTrusted( return true } else if strings.Contains(err.Error(), "execution reverted") { return false - } else { - t.Fatal(err) - return false } + t.Fatal(err) + return false }, time.Second*300, time.Second).Should(gomega.BeTrue()) } @@ -859,11 +864,11 @@ func setupAndFundSubscriptionAndConsumer( uni.backend.Commit() if vrfVersion == vrfcommon.V2Plus { - b, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) - require.NoError(t, err) - _, err = uni.linkContract.TransferAndCall( + b, err2 := utils.ABIEncode(`[{"type":"uint256"}]`, subID) + require.NoError(t, err2) + _, err2 = uni.linkContract.TransferAndCall( uni.sergey, coordinatorAddress, fundingAmount, b) - require.NoError(t, err, "failed to fund sub") + require.NoError(t, err2, "failed to fund sub") uni.backend.Commit() return } @@ -999,11 +1004,11 @@ func testSingleConsumerForcedFulfillment( // Wait for force-fulfillment to be queued. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - commitment, err := uni.oldRootContract.GetCommitment(nil, requestID) - require.NoError(t, err) + commitment, err2 := uni.oldRootContract.GetCommitment(nil, requestID) + require.NoError(t, err2) t.Log("commitment is:", hexutil.Encode(commitment[:])) - it, err := uni.vrfOwner.FilterRandomWordsForced(nil, []*big.Int{requestID}, []uint64{subID.Uint64()}, []common.Address{eoaConsumerAddr}) - require.NoError(t, err) + it, err2 := uni.vrfOwner.FilterRandomWordsForced(nil, []*big.Int{requestID}, []uint64{subID.Uint64()}, []common.Address{eoaConsumerAddr}) + require.NoError(t, err2) i := 0 for it.Next() { i++ @@ -1233,10 +1238,12 @@ func testSingleConsumerBigGasCallbackSandwich( } // Assert that we've completed 0 runs before adding 3 new requests. - runs, err := app.PipelineORM().GetAllRuns() - require.NoError(t, err) - assert.Equal(t, 0, len(runs)) - assert.Equal(t, 3, len(reqIDs)) + { + runs, err := app.PipelineORM().GetAllRuns() + require.NoError(t, err) + assert.Equal(t, 0, len(runs)) + assert.Equal(t, 3, len(reqIDs)) + } // Wait for the 50_000 gas randomness request to be enqueued. gomega.NewGomegaWithT(t).Eventually(func() bool { @@ -1263,9 +1270,11 @@ func testSingleConsumerBigGasCallbackSandwich( assertRandomWordsFulfilled(t, reqIDs[1], false, uni.rootContract, nativePayment) // Assert that we've still only completed 1 run before adding new requests. - runs, err = app.PipelineORM().GetAllRuns() - require.NoError(t, err) - assert.Equal(t, 1, len(runs)) + { + runs, err := app.PipelineORM().GetAllRuns() + require.NoError(t, err) + assert.Equal(t, 1, len(runs)) + } // Make some randomness requests, each one block apart, this time without a low-gas request present in the callbackGasLimit slice. callbackGasLimits = []uint32{2_500_000, 2_500_000, 2_500_000} @@ -1551,9 +1560,11 @@ func testConsumerProxyHappyPath( // Gas available will be around 724,385, which means that 750,000 - 724,385 = 25,615 gas was used. // This is ~20k more than what the non-proxied consumer uses. // So to be safe, users should probably over-estimate their fulfillment gas by ~25k. - gasAvailable, err := consumerContract.SGasAvailable(nil) - require.NoError(t, err) - t.Log("gas available after proxied callback:", gasAvailable) + { + gasAvailable, err := consumerContract.SGasAvailable(nil) + require.NoError(t, err) + t.Log("gas available after proxied callback:", gasAvailable) + } // Make the second randomness request and assert fulfillment is successful requestID2, _ := requestRandomnessAndAssertRandomWordsRequestedEvent( diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 2f20842aa57..33eb9f74839 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -8,7 +8,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" @@ -170,12 +169,12 @@ func newVRFCoordinatorV2PlusUniverse(t *testing.T, key ethkey.KeyV2, numConsumer ) for _, author := range vrfConsumers { // Deploy a VRF consumer. It has a starting balance of 500 LINK. - consumerContractAddress, _, consumerContract, err := + consumerContractAddress, _, consumerContract, err2 := vrfv2plus_consumer_example.DeployVRFV2PlusConsumerExample( author, backend, coordinatorAddress, linkAddress) - require.NoError(t, err, "failed to deploy VRFConsumer contract to simulated ethereum blockchain") - _, err = linkContract.Transfer(sergey, consumerContractAddress, assets.Ether(500).ToInt()) // Actually, LINK - require.NoError(t, err, "failed to send LINK to VRFConsumer contract on simulated ethereum blockchain") + require.NoError(t, err2, "failed to deploy VRFConsumer contract to simulated ethereum blockchain") + _, err2 = linkContract.Transfer(sergey, consumerContractAddress, assets.Ether(500).ToInt()) // Actually, LINK + require.NoError(t, err2, "failed to send LINK to VRFConsumer contract on simulated ethereum blockchain") consumerContracts = append(consumerContracts, vrftesthelpers.NewVRFV2PlusConsumer(consumerContract)) consumerContractAddresses = append(consumerContractAddresses, consumerContractAddress) @@ -1019,11 +1018,11 @@ func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { big.NewInt(1000000000000000000)) // 0.1 LINK require.NoError(tt, err) uni.backend.Commit() - subID, err := carolContract.SSubId(nil) - require.NoError(tt, err) - _, err = carolContract.TopUpSubscriptionNative(carol, + subID, err2 := carolContract.SSubId(nil) + require.NoError(tt, err2) + _, err2 = carolContract.TopUpSubscriptionNative(carol, big.NewInt(2000000000000000000)) // 0.2 ETH - require.NoError(tt, err) + require.NoError(tt, err2) gasRequested := 50_000 nw := 1 requestedIncomingConfs := 3 @@ -1071,11 +1070,11 @@ func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { consumerContract := uni.consumerProxyContract consumerContractAddress := uni.consumerProxyContractAddress - _, err = consumerContract.CreateSubscriptionAndFund(consumerOwner, assets.Ether(5).ToInt()) - require.NoError(t, err) + _, err2 := consumerContract.CreateSubscriptionAndFund(consumerOwner, assets.Ether(5).ToInt()) + require.NoError(t, err2) uni.backend.Commit() - subID, err := consumerContract.SSubId(nil) - require.NoError(t, err) + subID, err2 := consumerContract.SSubId(nil) + require.NoError(t, err2) gasRequested := 50_000 nw := 1 requestedIncomingConfs := 3 @@ -1098,15 +1097,6 @@ func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { }) } -func AssertEthBalances(t *testing.T, backend *backends.SimulatedBackend, addresses []common.Address, balances []*big.Int) { - require.Equal(t, len(addresses), len(balances)) - for i, a := range addresses { - b, err := backend.BalanceAt(testutils.Context(t), a, nil) - require.NoError(t, err) - assert.Equal(t, balances[i].String(), b.String(), "invalid balance for %v", a) - } -} - func setupSubscriptionAndFund( t *testing.T, uni coordinatorV2UniverseCommon, diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 1f6a9dd3f92..6dad3173072 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -222,9 +222,8 @@ func newVRFCoordinatorV2Universe(t *testing.T, key ethkey.KeyV2, numConsumers in backend.Commit() // Deploy old VRF v2 coordinator from bytecode - err, oldRootContractAddress, oldRootContract := deployOldCoordinator( + oldRootContractAddress, oldRootContract := deployOldCoordinator( t, linkAddress, bhsAddress, linkEthFeed, backend, neil) - require.NoError(t, err) // Deploy the VRFOwner contract, which will own the VRF coordinator // in some tests. @@ -252,12 +251,12 @@ func newVRFCoordinatorV2Universe(t *testing.T, key ethkey.KeyV2, numConsumers in ) for _, author := range vrfConsumers { // Deploy a VRF consumer. It has a starting balance of 500 LINK. - consumerContractAddress, _, consumerContract, err := + consumerContractAddress, _, consumerContract, err2 := vrf_consumer_v2.DeployVRFConsumerV2( author, backend, coordinatorAddress, linkAddress) - require.NoError(t, err, "failed to deploy VRFConsumer contract to simulated ethereum blockchain") - _, err = linkContract.Transfer(sergey, consumerContractAddress, assets.Ether(500).ToInt()) // Actually, LINK - require.NoError(t, err, "failed to send LINK to VRFConsumer contract on simulated ethereum blockchain") + require.NoError(t, err2, "failed to deploy VRFConsumer contract to simulated ethereum blockchain") + _, err2 = linkContract.Transfer(sergey, consumerContractAddress, assets.Ether(500).ToInt()) // Actually, LINK + require.NoError(t, err2, "failed to send LINK to VRFConsumer contract on simulated ethereum blockchain") consumerContracts = append(consumerContracts, vrftesthelpers.NewVRFConsumerV2(consumerContract)) consumerContractAddresses = append(consumerContractAddresses, consumerContractAddress) @@ -423,7 +422,6 @@ func deployOldCoordinator( backend *backends.SimulatedBackend, neil *bind.TransactOpts, ) ( - error, common.Address, *vrf_coordinator_v2.VRFCoordinatorV2, ) { @@ -447,7 +445,7 @@ func deployOldCoordinator( require.NotEqual(t, common.HexToAddress("0x0"), oldRootContractAddress, "old vrf coordinator address equal to zero address, deployment failed") oldRootContract, err := vrf_coordinator_v2.NewVRFCoordinatorV2(oldRootContractAddress, backend) require.NoError(t, err, "could not create wrapper object for old vrf coordinator v2") - return err, oldRootContractAddress, oldRootContract + return oldRootContractAddress, oldRootContract } // Send eth from prefunded account. @@ -799,8 +797,7 @@ func mineBatch(t *testing.T, requestIDs []*big.Int, subID *big.Int, backend *bac return gomega.NewWithT(t).Eventually(func() bool { backend.Commit() var txs []txmgr.DbEthTx - err := db.Select(&txs, query, subID.String()) - require.NoError(t, err) + require.NoError(t, db.Select(&txs, query, subID.String())) for _, tx := range txs { var evmTx txmgr.Tx tx.ToTx(&evmTx) @@ -1013,8 +1010,10 @@ func testEoa( // Make a randomness request with the EOA. This request is impossible to fulfill. numWords := uint32(1) minRequestConfirmations := uint16(2) - _, err := uni.rootContract.RequestRandomWords(consumer, keyHash, subID, minRequestConfirmations, uint32(200_000), numWords, false) - require.NoError(t, err) + { + _, err := uni.rootContract.RequestRandomWords(consumer, keyHash, subID, minRequestConfirmations, uint32(200_000), numWords, false) + require.NoError(t, err) + } uni.backend.Commit() // Ensure request is not fulfilled. @@ -1033,8 +1032,7 @@ func testEoa( q := pg.NewQ(app.GetSqlxDB(), app.Logger, app.Config.Database()) // Execute the query. - err = q.Select(&broadcastsBeforeFinality, query) - require.NoError(t, err) + require.NoError(t, q.Select(&broadcastsBeforeFinality, query)) // Ensure there is only one log broadcast (our EOA request), and that // it hasn't been marked as consumed yet. @@ -1056,8 +1054,7 @@ func testEoa( }, 5*time.Second, time.Second).Should(gomega.BeTrue()) // Execute the query for log broadcasts again after finality depth has elapsed. - err = q.Select(&broadcastsAfterFinality, query) - require.NoError(t, err) + require.NoError(t, q.Select(&broadcastsAfterFinality, query)) // Ensure that there is still only one log broadcast (our EOA request), but that // it has been marked as "consumed," such that it won't be retried. @@ -1184,8 +1181,8 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { // Wait for simulation to pass. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() - require.NoError(t, err) + runs, err2 := app.PipelineORM().GetAllRuns() + require.NoError(t, err2) t.Log("runs", len(runs)) return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) @@ -1264,8 +1261,8 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { // Wait for simulation to pass. gomega.NewGomegaWithT(t).Eventually(func() bool { uni.backend.Commit() - runs, err := app.PipelineORM().GetAllRuns() - require.NoError(t, err) + runs, err2 := app.PipelineORM().GetAllRuns() + require.NoError(t, err2) t.Log("runs", len(runs)) return len(runs) == 1 }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) @@ -1320,7 +1317,6 @@ func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore(t *testing.T } func TestVRFV2Integration_SingleConsumer_NeedsTrustedBlockhashStore_AfterDelay(t *testing.T) { - t.Skip("TODO: VRF-616") t.Parallel() ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2PlusUniverse(t, ownerKey, 2, true) @@ -1897,15 +1893,18 @@ func TestFulfillmentCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - vrfkey, err := app.GetKeyStore().VRF().Create() - require.NoError(t, err) - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) - uni.backend.Commit() - + var vrfkey vrfkey.KeyV2 + { + var err error + vrfkey, err = app.GetKeyStore().VRF().Create() + require.NoError(t, err) + p, err := vrfkey.PublicKey.Point() + require.NoError(t, err) + _, err = uni.rootContract.RegisterProvingKey( + uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) + require.NoError(t, err) + uni.backend.Commit() + } var ( nonProxiedConsumerGasEstimate uint64 proxiedConsumerGasEstimate uint64 @@ -1915,7 +1914,7 @@ func TestFulfillmentCost(t *testing.T) { carolContract := uni.consumerContracts[0] carolContractAddress := uni.consumerContractAddresses[0] - _, err = carolContract.CreateSubscriptionAndFund(carol, + _, err := carolContract.CreateSubscriptionAndFund(carol, big.NewInt(1000000000000000000)) // 0.1 LINK require.NoError(tt, err) uni.backend.Commit() @@ -1958,7 +1957,7 @@ func TestFulfillmentCost(t *testing.T) { consumerContract := uni.consumerProxyContract consumerContractAddress := uni.consumerProxyContractAddress - _, err = consumerContract.CreateSubscriptionAndFund(consumerOwner, assets.Ether(5).ToInt()) + _, err := consumerContract.CreateSubscriptionAndFund(consumerOwner, assets.Ether(5).ToInt()) require.NoError(t, err) uni.backend.Commit() subId, err := consumerContract.SSubId(nil) @@ -2007,7 +2006,7 @@ func TestStartingCountsV1(t *testing.T) { finalityDepth := 3 counts := vrf.GetStartingResponseCountsV1(q, lggr, 1337, uint32(finalityDepth)) assert.Equal(t, 0, len(counts)) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) err = ks.Unlock(testutils.Password) require.NoError(t, err) k, err := ks.Eth().Create(big.NewInt(1337)) @@ -2083,11 +2082,10 @@ func TestStartingCountsV1(t *testing.T) { unconfirmedTxes := []txmgr.Tx{} for i := int64(4); i < 6; i++ { reqID3 := utils.PadByteToHash(0x12) - md, err := json.Marshal(&txmgr.TxMeta{ + md, err2 := json.Marshal(&txmgr.TxMeta{ RequestID: &reqID3, }) - require.NoError(t, err) - md1 := datatypes.JSON(md) + require.NoError(t, err2) newNonce := evmtypes.Nonce(i + 1) unconfirmedTxes = append(unconfirmedTxes, txmgr.Tx{ Sequence: &newNonce, @@ -2097,7 +2095,7 @@ func TestStartingCountsV1(t *testing.T) { State: txmgrcommon.TxUnconfirmed, BroadcastAt: &b, InitialBroadcastAt: &b, - Meta: &md1, + Meta: (*datatypes.JSON)(&md), EncodedPayload: []byte{}, ChainID: chainID.ToInt(), }) @@ -2165,8 +2163,8 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit sql = `INSERT INTO evm.receipts (block_hash, tx_hash, block_number, transaction_index, receipt, created_at) VALUES (:block_hash, :tx_hash, :block_number, :transaction_index, :receipt, :created_at)` for _, r := range receipts { - _, err := db.NamedExec(sql, r) - require.NoError(t, err) + _, err2 := db.NamedExec(sql, r) + require.NoError(t, err2) } counts = vrf.GetStartingResponseCountsV1(q, lggr, 1337, uint32(finalityDepth)) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 6a1ad3e8b2e..31e76b48fdb 100644 --- a/core/services/vrf/v2/listener_v2.go +++ b/core/services/vrf/v2/listener_v2.go @@ -1,11 +1,13 @@ package v2 import ( + "cmp" "context" "database/sql" "fmt" "math" "math/big" + "slices" "strings" "sync" "time" @@ -20,7 +22,6 @@ import ( heaps "github.com/theodesp/go-heaps" "github.com/theodesp/go-heaps/pairing" "go.uber.org/multierr" - "golang.org/x/exp/slices" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -503,8 +504,8 @@ func (lsn *listenerV2) processPendingVRFRequests(ctx context.Context) { // first. This allows us to break out of the processing loop as early as possible // in the event that a subscription is too underfunded to have it's // requests processed. - slices.SortFunc(reqs, func(a, b pendingRequest) bool { - return a.req.CallbackGasLimit() < b.req.CallbackGasLimit() + slices.SortFunc(reqs, func(a, b pendingRequest) int { + return cmp.Compare(a.req.CallbackGasLimit(), b.req.CallbackGasLimit()) }) p := lsn.processRequestsPerSub(ctx, sID, startLinkBalance, startEthBalance, reqs, subIsActive) @@ -917,7 +918,7 @@ func (lsn *listenerV2) enqueueForceFulfillment( requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) subID := p.req.req.SubID() requestTxHash := p.req.req.Raw().TxHash - etx, err = lsn.txm.CreateTransaction(txmgr.TxRequest{ + etx, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.vrfOwner.Address(), EncodedPayload: txData, @@ -1124,7 +1125,7 @@ func (lsn *listenerV2) processRequestsPerSubHelper( requestID := common.BytesToHash(p.req.req.RequestID().Bytes()) coordinatorAddress := lsn.coordinator.Address() requestTxHash := p.req.req.Raw().TxHash - transaction, err = lsn.txm.CreateTransaction(txmgr.TxRequest{ + transaction, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.coordinator.Address(), EncodedPayload: hexutil.MustDecode(p.payload), diff --git a/core/services/vrf/v2/listener_v2_helpers_test.go b/core/services/vrf/v2/listener_v2_helpers_test.go index 204d1e1fcab..8ba900bdc3a 100644 --- a/core/services/vrf/v2/listener_v2_helpers_test.go +++ b/core/services/vrf/v2/listener_v2_helpers_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/assets" - "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" + v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" ) func TestListener_EstimateFeeJuels(t *testing.T) { diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 77e279d8f7c..70d5b8154e0 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -153,7 +153,7 @@ func testMaybeSubtractReservedLink(t *testing.T, vrfVersion vrfcommon.Version) { lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) q := pg.NewQ(db, lggr, cfg) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) chainID := uint64(1337) k, err := ks.Eth().Create(big.NewInt(int64(chainID))) @@ -220,7 +220,7 @@ func testMaybeSubtractReservedNative(t *testing.T, vrfVersion vrfcommon.Version) lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) q := pg.NewQ(db, lggr, cfg) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) chainID := uint64(1337) k, err := ks.Eth().Create(big.NewInt(int64(chainID))) @@ -283,7 +283,7 @@ func TestMaybeSubtractReservedNativeV2(t *testing.T) { lggr := logger.TestLogger(t) cfg := pgtest.NewQConfig(false) q := pg.NewQ(db, lggr, cfg) - ks := keystore.New(db, utils.FastScryptParams, lggr, cfg) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) require.NoError(t, ks.Unlock("blah")) chainID := uint64(1337) subID := new(big.Int).SetUint64(1) diff --git a/core/services/vrf/v2/listener_v2_types.go b/core/services/vrf/v2/listener_v2_types.go index e8c3a8ccb13..e0596abcd1a 100644 --- a/core/services/vrf/v2/listener_v2_types.go +++ b/core/services/vrf/v2/listener_v2_types.go @@ -113,6 +113,8 @@ func (lsn *listenerV2) processBatch( fromAddress common.Address, ) (processedRequestIDs []string) { start := time.Now() + ctx, cancel := lsn.chStop.NewCtx() + defer cancel() // Enqueue a single batch tx for requests that we're able to fulfill based on whether // they passed simulation or not. @@ -179,7 +181,7 @@ func (lsn *listenerV2) processBatch( for _, reqID := range batch.reqIDs { reqIDHashes = append(reqIDHashes, common.BytesToHash(reqID.Bytes())) } - ethTX, err = lsn.txm.CreateTransaction(txmgr.TxRequest{ + ethTX, err = lsn.txm.CreateTransaction(ctx, txmgr.TxRequest{ FromAddress: fromAddress, ToAddress: lsn.batchCoordinator.Address(), EncodedPayload: payload, diff --git a/core/services/vrf/vrftesthelpers/consumer_v2.go b/core/services/vrf/vrftesthelpers/consumer_v2.go index ec3d727f7ab..abaf97b828b 100644 --- a/core/services/vrf/vrftesthelpers/consumer_v2.go +++ b/core/services/vrf/vrftesthelpers/consumer_v2.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2_plus_upgradeable_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2_upgradeable_example" diff --git a/core/services/vrf/vrftesthelpers/helpers.go b/core/services/vrf/vrftesthelpers/helpers.go index 15af16f6fd9..f36fb1ea027 100644 --- a/core/services/vrf/vrftesthelpers/helpers.go +++ b/core/services/vrf/vrftesthelpers/helpers.go @@ -51,7 +51,7 @@ func CreateAndStartBHSJob( app *cltest.TestApplication, bhsAddress, coordinatorV1Address, coordinatorV2Address, coordinatorV2PlusAddress string, trustedBlockhashStoreAddress string, trustedBlockhashStoreBatchSize int32, lookback int, - heartbeatPeriod time.Duration, + heartbeatPeriod time.Duration, waitBlocks int, ) job.Job { jid := uuid.New() s := testspecs.GenerateBlockhashStoreSpec(testspecs.BlockhashStoreSpecParams{ @@ -60,7 +60,7 @@ func CreateAndStartBHSJob( CoordinatorV1Address: coordinatorV1Address, CoordinatorV2Address: coordinatorV2Address, CoordinatorV2PlusAddress: coordinatorV2PlusAddress, - WaitBlocks: 100, + WaitBlocks: waitBlocks, LookbackBlocks: lookback, HeartbeatPeriod: heartbeatPeriod, BlockhashStoreAddress: bhsAddress, diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index ca85a4d1621..f5a8d553f23 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -69,7 +69,7 @@ func (d *Delegate) BeforeJobDeleted(spec job.Job) { func (d *Delegate) OnDeleteJob(jb job.Job, q pg.Queryer) error { return nil } // ServicesForSpec satisfies the job.Delegate interface. -func (d *Delegate) ServicesForSpec(spec job.Job, qopts ...pg.QOpt) ([]job.ServiceCtx, error) { +func (d *Delegate) ServicesForSpec(spec job.Job) ([]job.ServiceCtx, error) { service := &pseudoService{ spec: spec, webhookJobRunner: d.webhookJobRunner, diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index 4892ebf97a4..a94f2ffe97d 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -64,13 +64,12 @@ func (_m *ExternalInitiatorManager) Notify(webhookSpecID int32) error { return r0 } -type mockConstructorTestingTNewExternalInitiatorManager interface { +// NewExternalInitiatorManager creates a new instance of ExternalInitiatorManager. 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 NewExternalInitiatorManager(t interface { mock.TestingT Cleanup(func()) -} - -// NewExternalInitiatorManager creates a new instance of ExternalInitiatorManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewExternalInitiatorManager(t mockConstructorTestingTNewExternalInitiatorManager) *ExternalInitiatorManager { +}) *ExternalInitiatorManager { mock := &ExternalInitiatorManager{} mock.Mock.Test(t) diff --git a/core/services/webhook/mocks/http_client.go b/core/services/webhook/mocks/http_client.go index f2c7978f0ae..b5b448a56d0 100644 --- a/core/services/webhook/mocks/http_client.go +++ b/core/services/webhook/mocks/http_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -39,13 +39,12 @@ func (_m *HTTPClient) Do(req *http.Request) (*http.Response, error) { return r0, r1 } -type mockConstructorTestingTNewHTTPClient interface { +// NewHTTPClient creates a new instance of HTTPClient. 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 NewHTTPClient(t interface { mock.TestingT Cleanup(func()) -} - -// NewHTTPClient creates a new instance of HTTPClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewHTTPClient(t mockConstructorTestingTNewHTTPClient) *HTTPClient { +}) *HTTPClient { mock := &HTTPClient{} mock.Mock.Test(t) diff --git a/core/sessions/mocks/orm.go b/core/sessions/mocks/orm.go index f54bd898e15..5699b9f8892 100644 --- a/core/sessions/mocks/orm.go +++ b/core/sessions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. +// Code generated by mockery v2.35.4. DO NOT EDIT. package mocks @@ -378,13 +378,12 @@ func (_m *ORM) UpdateRole(email string, newRole string) (sessions.User, error) { return r0, r1 } -type mockConstructorTestingTNewORM interface { +// NewORM creates a new instance of ORM. 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 NewORM(t interface { mock.TestingT Cleanup(func()) -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewORM(t mockConstructorTestingTNewORM) *ORM { +}) *ORM { mock := &ORM{} mock.Mock.Test(t) diff --git a/core/sessions/orm_test.go b/core/sessions/orm_test.go index 804ea2dbb87..5decb823086 100644 --- a/core/sessions/orm_test.go +++ b/core/sessions/orm_test.go @@ -34,8 +34,8 @@ func TestORM_FindUser(t *testing.T) { t.Parallel() db, orm := setupORM(t) - user1 := cltest.MustNewUser(t, "test1@email1.net", cltest.Password) - user2 := cltest.MustNewUser(t, "test2@email2.net", cltest.Password) + user1 := cltest.MustRandomUser(t) + user2 := cltest.MustRandomUser(t) require.NoError(t, orm.CreateUser(&user1)) require.NoError(t, orm.CreateUser(&user2)) @@ -56,12 +56,11 @@ func TestORM_AuthorizedUserWithSession(t *testing.T) { sessionID string sessionDuration time.Duration wantError string - wantEmail string }{ - {"authorized", "correctID", cltest.MustParseDuration(t, "3m"), "", "have@email"}, - {"expired", "correctID", cltest.MustParseDuration(t, "0m"), sessions.ErrUserSessionExpired.Error(), ""}, - {"incorrect", "wrong", cltest.MustParseDuration(t, "3m"), sessions.ErrUserSessionExpired.Error(), ""}, - {"empty", "", cltest.MustParseDuration(t, "3m"), sessions.ErrEmptySessionID.Error(), ""}, + {"authorized", "correctID", cltest.MustParseDuration(t, "3m"), ""}, + {"expired", "correctID", cltest.MustParseDuration(t, "0m"), sessions.ErrUserSessionExpired.Error()}, + {"incorrect", "wrong", cltest.MustParseDuration(t, "3m"), sessions.ErrUserSessionExpired.Error()}, + {"empty", "", cltest.MustParseDuration(t, "3m"), sessions.ErrEmptySessionID.Error()}, } for _, test := range tests { @@ -69,7 +68,7 @@ func TestORM_AuthorizedUserWithSession(t *testing.T) { db := pgtest.NewSqlxDB(t) orm := sessions.NewORM(db, test.sessionDuration, logger.TestLogger(t), pgtest.NewQConfig(true), &audit.AuditLoggerService{}) - user := cltest.MustNewUser(t, "have@email", cltest.Password) + user := cltest.MustRandomUser(t) require.NoError(t, orm.CreateUser(&user)) prevSession := cltest.NewSession("correctID") @@ -83,7 +82,7 @@ func TestORM_AuthorizedUserWithSession(t *testing.T) { require.EqualError(t, err, test.wantError) } else { require.NoError(t, err) - assert.Equal(t, test.wantEmail, actual.Email) + assert.Equal(t, user.Email, actual.Email) var bumpedSession sessions.Session err = db.Get(&bumpedSession, "SELECT * FROM sessions WHERE ID = $1", prevSession.ID) require.NoError(t, err) @@ -97,13 +96,13 @@ func TestORM_DeleteUser(t *testing.T) { t.Parallel() _, orm := setupORM(t) - _, err := orm.FindUser(cltest.APIEmailAdmin) - require.NoError(t, err) + u := cltest.MustRandomUser(t) + require.NoError(t, orm.CreateUser(&u)) - err = orm.DeleteUser(cltest.APIEmailAdmin) + err := orm.DeleteUser(u.Email) require.NoError(t, err) - _, err = orm.FindUser(cltest.APIEmailAdmin) + _, err = orm.FindUser(u.Email) require.Error(t, err) } @@ -112,14 +111,17 @@ func TestORM_DeleteUserSession(t *testing.T) { db, orm := setupORM(t) + u := cltest.MustRandomUser(t) + require.NoError(t, orm.CreateUser(&u)) + session := sessions.NewSession() - _, err := db.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, cltest.APIEmailAdmin) + _, err := db.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, u.Email) require.NoError(t, err) err = orm.DeleteUserSession(session.ID) require.NoError(t, err) - _, err = orm.FindUser(cltest.APIEmailAdmin) + _, err = orm.FindUser(u.Email) require.NoError(t, err) sessions, err := orm.Sessions(0, 10) @@ -130,14 +132,17 @@ func TestORM_DeleteUserSession(t *testing.T) { func TestORM_DeleteUserCascade(t *testing.T) { db, orm := setupORM(t) + u := cltest.MustRandomUser(t) + require.NoError(t, orm.CreateUser(&u)) + session := sessions.NewSession() - _, err := db.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, cltest.APIEmailAdmin) + _, err := db.Exec("INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, now(), now())", session.ID, u.Email) require.NoError(t, err) - err = orm.DeleteUser(cltest.APIEmailAdmin) + err = orm.DeleteUser(u.Email) require.NoError(t, err) - _, err = orm.FindUser(cltest.APIEmailAdmin) + _, err = orm.FindUser(u.Email) require.Error(t, err) sessions, err := orm.Sessions(0, 10) diff --git a/core/sessions/reaper_test.go b/core/sessions/reaper_test.go index d095a23edd5..a96c3822ef5 100644 --- a/core/sessions/reaper_test.go +++ b/core/sessions/reaper_test.go @@ -1,7 +1,6 @@ package sessions_test import ( - "database/sql" "testing" "time" @@ -12,7 +11,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -36,6 +34,7 @@ func TestSessionReaper_ReapSessions(t *testing.T) { orm := sessions.NewORM(db, config.SessionTimeout().Duration(), lggr, pgtest.NewQConfig(true), audit.NoopLogger) r := sessions.NewSessionReaper(db.DB, config, lggr) + t.Cleanup(func() { assert.NoError(t, r.Stop()) }) @@ -54,34 +53,32 @@ func TestSessionReaper_ReapSessions(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - t.Cleanup(func() { - clearSessions(t, db.DB) - }) + user := cltest.MustRandomUser(t) + require.NoError(t, orm.CreateUser(&user)) - _, err := db.Exec("INSERT INTO sessions (last_used, email, id, created_at) VALUES ($1, $2, $3, now())", test.lastUsed, cltest.APIEmailAdmin, test.name) + session := sessions.NewSession() + session.Email = user.Email + + _, err := db.Exec("INSERT INTO sessions (last_used, email, id, created_at) VALUES ($1, $2, $3, now())", test.lastUsed, user.Email, test.name) require.NoError(t, err) + t.Cleanup(func() { + _, err2 := db.Exec("DELETE FROM sessions where email = $1", user.Email) + require.NoError(t, err2) + }) + r.WakeUp() + <-r.(interface { + WorkDone() <-chan struct{} + }).WorkDone() + sessions, err := orm.Sessions(0, 10) + assert.NoError(t, err) if test.wantReap { - gomega.NewWithT(t).Eventually(func() []sessions.Session { - sessions, err := orm.Sessions(0, 10) - assert.NoError(t, err) - return sessions - }).Should(gomega.HaveLen(0)) + assert.Len(t, sessions, 0) } else { - gomega.NewWithT(t).Consistently(func() []sessions.Session { - sessions, err := orm.Sessions(0, 10) - assert.NoError(t, err) - return sessions - }).Should(gomega.HaveLen(1)) + assert.Len(t, sessions, 1) } }) } } - -// clearSessions removes all sessions. -func clearSessions(t *testing.T, db *sql.DB) { - _, err := db.Exec("DELETE FROM sessions") - require.NoError(t, err) -} diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index d6135ce4529..7a1e38fb030 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -15,12 +15,16 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/migrate" @@ -437,3 +441,141 @@ func TestSetMigrationENVVars(t *testing.T) { require.Equal(t, actualChainID, chainID.String()) }) } + +func TestDatabaseBackFillWithMigration202(t *testing.T) { + _, db := heavyweight.FullTestDBEmptyV2(t, migrationDir, nil) + + err := goose.UpTo(db.DB, migrationDir, 201) + require.NoError(t, err) + + simulatedOrm := logpoller.NewORM(testutils.SimulatedChainID, db, logger.TestLogger(t), pgtest.NewQConfig(true)) + require.NoError(t, simulatedOrm.InsertBlock(testutils.Random32Byte(), 10, time.Now(), 0), err) + require.NoError(t, simulatedOrm.InsertBlock(testutils.Random32Byte(), 51, time.Now(), 0), err) + require.NoError(t, simulatedOrm.InsertBlock(testutils.Random32Byte(), 90, time.Now(), 0), err) + require.NoError(t, simulatedOrm.InsertBlock(testutils.Random32Byte(), 120, time.Now(), 23), err) + + baseOrm := logpoller.NewORM(big.NewInt(int64(84531)), db, logger.TestLogger(t), pgtest.NewQConfig(true)) + require.NoError(t, baseOrm.InsertBlock(testutils.Random32Byte(), 400, time.Now(), 0), err) + + klaytnOrm := logpoller.NewORM(big.NewInt(int64(1001)), db, logger.TestLogger(t), pgtest.NewQConfig(true)) + require.NoError(t, klaytnOrm.InsertBlock(testutils.Random32Byte(), 100, time.Now(), 0), err) + + err = goose.UpTo(db.DB, migrationDir, 202) + require.NoError(t, err) + + tests := []struct { + name string + blockNumber int64 + expectedFinalizedBlock int64 + orm *logpoller.DbORM + }{ + { + name: "last finalized block not changed if finality is too deep", + blockNumber: 10, + expectedFinalizedBlock: 0, + orm: simulatedOrm, + }, + { + name: "last finalized block is updated for first block", + blockNumber: 51, + expectedFinalizedBlock: 1, + orm: simulatedOrm, + }, + { + name: "last finalized block is updated", + blockNumber: 90, + expectedFinalizedBlock: 40, + orm: simulatedOrm, + }, + { + name: "last finalized block is not changed when finality is set", + blockNumber: 120, + expectedFinalizedBlock: 23, + orm: simulatedOrm, + }, + { + name: "use non default finality depth for chain 84531", + blockNumber: 400, + expectedFinalizedBlock: 200, + orm: baseOrm, + }, + { + name: "use default finality depth for chain 1001", + blockNumber: 100, + expectedFinalizedBlock: 99, + orm: klaytnOrm, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + block, err := tt.orm.SelectBlockByNumber(tt.blockNumber) + require.NoError(t, err) + require.Equal(t, tt.expectedFinalizedBlock, block.FinalizedBlockNumber) + }) + } +} + +func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { + previousMigration := int64(201) + backfillMigration := int64(202) + chainCount := 2 + // By default, log poller keeps up to 100_000 blocks in the database, this is the pessimistic case + maxLogsSize := 100_000 + // Disable Goose logging for benchmarking + goose.SetLogger(goose.NopLogger()) + _, db := heavyweight.FullTestDBEmptyV2(b, migrationDir, nil) + + err := goose.UpTo(db.DB, migrationDir, previousMigration) + require.NoError(b, err) + + q := pg.NewQ(db, logger.NullLogger, pgtest.NewQConfig(true)) + for j := 0; j < chainCount; j++ { + // Insert 100_000 block to database, can't do all at once, so batching by 10k + var blocks []logpoller.LogPollerBlock + for i := 0; i < maxLogsSize; i++ { + blocks = append(blocks, logpoller.LogPollerBlock{ + EvmChainId: utils.NewBigI(int64(j + 1)), + BlockHash: testutils.Random32Byte(), + BlockNumber: int64(i + 1000), + FinalizedBlockNumber: 0, + }) + } + batchInsertSize := 10_000 + for i := 0; i < maxLogsSize; i += batchInsertSize { + start, end := i, i+batchInsertSize + if end > maxLogsSize { + end = maxLogsSize + } + + err = q.ExecQNamed(` + INSERT INTO evm.log_poller_blocks + (evm_chain_id, block_hash, block_number, finalized_block_number, block_timestamp, created_at) + VALUES + (:evm_chain_id, :block_hash, :block_number, :finalized_block_number, NOW(), NOW()) + ON CONFLICT DO NOTHING`, blocks[start:end]) + require.NoError(b, err) + } + } + + b.ResetTimer() + + // 1. Measure time of migration 200 + // 2. Goose down to 199 + // 3. Reset last_finalized_block_number to 0 + // Repeat 1-3 + for i := 0; i < b.N; i++ { + b.StartTimer() + err = goose.UpTo(db.DB, migrationDir, backfillMigration) + require.NoError(b, err) + b.StopTimer() + + // Cleanup + err = goose.DownTo(db.DB, migrationDir, previousMigration) + require.NoError(b, err) + + err = q.ExecQ(` + UPDATE evm.log_poller_blocks + SET finalized_block_number = 0`) + require.NoError(b, err) + } +} diff --git a/core/store/migrate/migrations/0194_evm_schema.sql b/core/store/migrate/migrations/0194_evm_schema.sql index fc55028c16e..65b9bddd6d7 100644 --- a/core/store/migrate/migrations/0194_evm_schema.sql +++ b/core/store/migrate/migrations/0194_evm_schema.sql @@ -162,3 +162,4 @@ CREATE TRIGGER notify_eth_tx_insertion AFTER INSERT ON public.eth_txes FOR EACH -- +goose StatementEnd DROP SCHEMA evm; +SET search_path TO public; \ No newline at end of file diff --git a/core/store/migrate/migrations/0198_add_block_timestamp_index.sql b/core/store/migrate/migrations/0198_add_block_timestamp_index.sql new file mode 100644 index 00000000000..8f20f4d8491 --- /dev/null +++ b/core/store/migrate/migrations/0198_add_block_timestamp_index.sql @@ -0,0 +1,5 @@ +-- +goose Up +create index log_poller_blocks_by_timestamp on evm.log_poller_blocks (evm_chain_id, block_timestamp); + +-- +goose Down +DROP INDEX IF EXISTS evm.log_poller_blocks_by_timestamp; \ No newline at end of file diff --git a/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql b/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql new file mode 100644 index 00000000000..07cdfb02452 --- /dev/null +++ b/core/store/migrate/migrations/0199_remove_next_nonce_from_keystore.sql @@ -0,0 +1,9 @@ +-- +goose Up + +ALTER TABLE evm.key_states DROP COLUMN next_nonce; +ALTER TABLE keys DROP COLUMN next_nonce; + +-- +goose Down + +ALTER TABLE evm.key_states ADD next_nonce bigint NOT NULL DEFAULT 0; +ALTER TABLE keys ADD next_nonce bigint NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql b/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql new file mode 100644 index 00000000000..544a81f2878 --- /dev/null +++ b/core/store/migrate/migrations/0200_evm_logs_add_block_timestamp_index.sql @@ -0,0 +1,15 @@ +-- +goose Up + +-- Start with dropping the index introduced in a previous migration - we are not going to use it +DROP INDEX IF EXISTS evm.log_poller_blocks_by_timestamp; + +CREATE INDEX evm_logs_by_timestamp + ON evm.logs (evm_chain_id, address, event_sig, block_timestamp, block_number); + +-- +goose Down +create index log_poller_blocks_by_timestamp on evm.log_poller_blocks (evm_chain_id, block_timestamp); + +drop index if exists evm.evm_logs_by_timestamp; + + + diff --git a/core/store/migrate/migrations/0201_add_finalized_block_number.sql b/core/store/migrate/migrations/0201_add_finalized_block_number.sql new file mode 100644 index 00000000000..db15ebbed6e --- /dev/null +++ b/core/store/migrate/migrations/0201_add_finalized_block_number.sql @@ -0,0 +1,11 @@ +-- +goose Up +ALTER TABLE evm.log_poller_blocks + ADD COLUMN finalized_block_number + bigint not null + default 0 + check (finalized_block_number >= 0); + + +-- +goose Down +ALTER TABLE evm.log_poller_blocks + DROP COLUMN finalized_block_number; diff --git a/core/store/migrate/migrations/0202_default_values_for_last_finalized_block.sql b/core/store/migrate/migrations/0202_default_values_for_last_finalized_block.sql new file mode 100644 index 00000000000..0f93cd27482 --- /dev/null +++ b/core/store/migrate/migrations/0202_default_values_for_last_finalized_block.sql @@ -0,0 +1,33 @@ +-- +goose Up + +WITH variables AS ( + SELECT + evm_chain_id, + CASE + WHEN evm_chain_id = 43113 then 1 -- Avax Fuji + WHEN evm_chain_id = 43114 then 1 -- Avax Mainnet + WHEN evm_chain_id = 84531 THEN 200 -- Base Goerli + WHEN evm_chain_id = 8453 THEN 200 -- Base Mainnet + WHEN evm_chain_id = 42220 THEN 1 -- Celo Mainnet + WHEN evm_chain_id = 44787 THEN 1 -- Celo Testnet + WHEN evm_chain_id = 8217 THEN 1 -- Klaytn Mainnet + WHEN evm_chain_id = 1001 THEN 1 -- Klaytn Mainnet + WHEN evm_chain_id = 1088 THEN 1 -- Metis Mainnet + WHEN evm_chain_id = 588 THEN 1 -- Metis Rinkeby + WHEN evm_chain_id = 420 THEN 200 -- Optimism Goerli + WHEN evm_chain_id = 10 THEN 200 -- Optimism Mainnet + WHEN evm_chain_id = 137 THEN 500 -- Polygon Mainnet + WHEN evm_chain_id = 80001 THEN 500 -- Polygon Mumbai + WHEN evm_chain_id = 534352 THEN 1 -- Scroll Mainnet + WHEN evm_chain_id = 534351 THEN 1 -- Scroll Sepolia + ELSE 50 -- all other chains + END AS finality_depth + FROM evm.log_poller_blocks + GROUP BY evm_chain_id +) + +UPDATE evm.log_poller_blocks AS lpb +SET finalized_block_number = greatest(lpb.block_number - v.finality_depth, 0) +FROM variables v +WHERE lpb.evm_chain_id = v.evm_chain_id + AND lpb.finalized_block_number = 0; \ No newline at end of file diff --git a/core/store/migrate/migrations/0203_search_path.sql b/core/store/migrate/migrations/0203_search_path.sql new file mode 100644 index 00000000000..06213067ae4 --- /dev/null +++ b/core/store/migrate/migrations/0203_search_path.sql @@ -0,0 +1,4 @@ +-- +goose Up +-- BFC-2694 - fix search path so public takes precedence. No need for a downward migration. +SET search_path TO public,evm; + diff --git a/core/store/migrate/migrations/0204_create_eal_tables.sql b/core/store/migrate/migrations/0204_create_eal_tables.sql new file mode 100644 index 00000000000..8a8d20a9001 --- /dev/null +++ b/core/store/migrate/migrations/0204_create_eal_tables.sql @@ -0,0 +1,97 @@ +-- +goose Up +CREATE TABLE eal_specs ( + id BIGSERIAL PRIMARY KEY, + forwarder_address BYTEA NOT NULL, + evm_chain_id NUMERIC(78) NOT NULL, + from_addresses BYTEA[] DEFAULT '{}' NOT NULL, + lookback_blocks BIGINT NOT NULL, + poll_period BIGINT NOT NULL, + run_timeout BIGINT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL, + CONSTRAINT forwarder_address_len_chk CHECK ( + octet_length(forwarder_address) = 20 + ) +); + +ALTER TABLE + jobs +ADD + COLUMN eal_spec_id INT REFERENCES eal_specs (id), +DROP + CONSTRAINT chk_only_one_spec, +ADD + CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id + ) = 1 + ); + +CREATE TABLE eal_txs ( + request_id TEXT PRIMARY KEY, + forwarder_address BYTEA NOT NULL, + from_address BYTEA NOT NULL, + target_address BYTEA NOT NULL, + evm_chain_id NUMERIC(78) NOT NULL, + payload BYTEA NOT NULL, + tx_status TEXT NOT NULL, + gas_limit BIGINT NOT NULL, + ccip_message_id BYTEA, + failure_reason TEXT, + status_update_url TEXT, + tx_hash BYTEA, + tx_id BIGINT REFERENCES txes INITIALLY DEFERRED, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL, + CONSTRAINT forwarder_address_len_chk CHECK ( + octet_length(forwarder_address) = 20 + ), + CONSTRAINT target_address_len_chk CHECK ( + octet_length(target_address) = 20 + ), + CONSTRAINT from_address_len_chk CHECK ( + octet_length(from_address) = 20 + ), + CONSTRAINT ccip_message_id_len_chk CHECK ( + octet_length(ccip_message_id) = 32 + ), + CONSTRAINT tx_hash_len_chk CHECK ( + octet_length(tx_hash) = 32 + ) +); +CREATE INDEX idx_eal_txs_chain_id_tx_status ON eal_txs(evm_chain_id, tx_status); + +-- +goose Down +ALTER TABLE + jobs +DROP + CONSTRAINT chk_only_one_spec, +ADD + CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id + ) = 1 + ); +ALTER TABLE + jobs +DROP + COLUMN eal_spec_id; +DROP + TABLE IF EXISTS eal_specs; +DROP + TABLE IF EXISTS eal_txs; diff --git a/core/store/models/errors.go b/core/store/models/errors.go index 9a4317e2dbc..6feddd96c03 100644 --- a/core/store/models/errors.go +++ b/core/store/models/errors.go @@ -1,6 +1,7 @@ package models import ( + "errors" "strings" ) @@ -49,12 +50,13 @@ func (jae *JSONAPIErrors) Add(detail string) { // Merge combines the arrays of the passed error if it is of type JSONAPIErrors, // otherwise simply adds a single error with the error string as detail. func (jae *JSONAPIErrors) Merge(e error) { - switch typed := e.(type) { - case *JSONAPIErrors: - jae.Errors = append(jae.Errors, typed.Errors...) - default: - jae.Add(e.Error()) + var jsonErr *JSONAPIErrors + if errors.As(e, &jsonErr) { + jae.Errors = append(jae.Errors, jsonErr.Errors...) + return } + jae.Add(e.Error()) + } // CoerceEmptyToNil will return nil if JSONAPIErrors has no errors. diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 3dd7c675d50..beda7354566 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -15,11 +15,11 @@ import ( ) var ( - CronSpec = ` + CronSpecTemplate = ` type = "cron" schemaVersion = 1 schedule = "CRON_TZ=UTC * 0 0 1 1 *" -externalJobID = "123e4567-e89b-12d3-a456-426655440003" +externalJobID = "%s" observationSource = """ ds [type=http method=GET url="https://chain.link/ETH-USD"]; ds_parse [type=jsonparse path="data,price"]; @@ -27,11 +27,11 @@ ds_multiply [type=multiply times=100]; ds -> ds_parse -> ds_multiply; """ ` - CronSpecDotSep = ` + CronSpecDotSepTemplate = ` type = "cron" schemaVersion = 1 schedule = "CRON_TZ=UTC * 0 0 1 1 *" -externalJobID = "123e4567-e89b-12d3-a456-426655440013" +externalJobID = "%s" observationSource = """ ds [type=http method=GET url="https://chain.link/ETH-USD"]; ds_parse [type=jsonparse path="data.price" separator="."]; @@ -52,12 +52,12 @@ observationSource = """ ds1 -> ds1_parse -> ds1_multiply; """ ` - DirectRequestSpec = ` + DirectRequestSpecTemplate = ` type = "directrequest" schemaVersion = 1 -name = "example eth request event spec" +name = "%s" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "123e4567-e89b-12d3-a456-426655440004" +externalJobID = "%s" evmChainID = "0" observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; @@ -66,14 +66,14 @@ observationSource = """ ds1 -> ds1_parse -> ds1_multiply; """ ` - DirectRequestSpecWithRequestersAndMinContractPayment = ` + DirectRequestSpecWithRequestersAndMinContractPaymentTemplate = ` type = "directrequest" schemaVersion = 1 requesters = ["0xaaaa1F8ee20f5565510B84f9353F1E333E753B7a", "0xbbbb70F0e81C6F3430dfdC9fa02fB22BdD818C4e"] minContractPaymentLinkJuels = "1000000000000000000000" -name = "example eth request event spec with requesters and min contract payment" +name = "%s" contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "123e4567-e89b-12d3-a456-426655440014" +externalJobID = "%s" evmChainID = 0 observationSource = """ ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; @@ -82,12 +82,12 @@ observationSource = """ ds1 -> ds1_parse -> ds1_multiply; """ ` - FluxMonitorSpec = ` + FluxMonitorSpecTemplate = ` type = "fluxmonitor" schemaVersion = 1 -name = "example flux monitor spec" +name = "%s" contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -externalJobID = "123e4567-e89b-12d3-a456-426655440005" +externalJobID = "%s" evmChainID = 0 threshold = 0.5 absoluteThreshold = 0.0 # optional @@ -113,47 +113,10 @@ ds2 -> ds2_parse -> answer1; answer1 [type=median index=0]; """ ` - OCR2SolanaSpecMinimal = `type = "offchainreporting2" -schemaVersion = 1 -name = "local testing job" -contractID = "VT3AvPr2nyE9Kr7ydDXVvgvJXyBr9tHA5hd6a1GBGBx" -p2pv2Bootstrappers = [] -relay = "solana" -pluginType = "median" -transmitterID = "8AuzafoGEz92Z3WGFfKuEh2Ca794U3McLJBy7tfmDynK" -observationSource = """ -""" -[pluginConfig] -juelsPerFeeCoinSource = """ -""" - -[relayConfig] -ocr2ProgramID = "CF13pnKGJ1WJZeEgVAtFdUi4MMndXm9hneiHs8azUaZt" -storeProgramID = "A7Jh2nb1hZHwqEofm4N8SXbKTj82rx7KUfjParQXUyMQ" -transmissionsID = "J6RRmA39u8ZBwrMvRPrJA3LMdg73trb6Qhfo8vjSeadg" -chainID = "Chainlink-99"` - - OCR2CosmosSpecMinimal = `type = "offchainreporting2" -schemaVersion = 1 -name = "local testing job" -contractID = "wasm1ysjdehnf3a3kpndx74yyg6ry90258y4z5vawjz" -isBootstrapPeer = false -p2pv2Bootstrappers = [] -relay = "cosmos" -transmitterID = "wasm1ysjdehnf3a3kpndx74yyg6ry90258y4z5vawjz" -observationSource = """ -""" -juelsPerFeeCoinSource = """ -""" - -[relayConfig] -chainID = "Chainlink-99"` - OCR2CosmosNodeSpecMinimal = OCR2CosmosSpecMinimal + ` -nodeName = "some-test-node"` - OCR2EVMSpecMinimal = `type = "offchainreporting2" + OCR2EVMSpecMinimalTemplate = `type = "offchainreporting2" schemaVersion = 1 -name = "local testing job" +name = "%s" relay = "evm" contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pv2Bootstrappers = [] @@ -169,10 +132,10 @@ observationSource = """ chainID = 0 [pluginConfig] ` - WebhookSpecNoBody = ` + WebhookSpecNoBodyTemplate = ` type = "webhook" schemaVersion = 1 -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F53" +externalJobID = "%s" observationSource = """ fetch [type=bridge name="%s"] parse_request [type=jsonparse path="data,result"]; @@ -183,10 +146,10 @@ observationSource = """ """ ` - WebhookSpecWithBody = ` + WebhookSpecWithBodyTemplate = ` type = "webhook" schemaVersion = 1 -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F54" +externalJobID = "%s" observationSource = """ parse_request [type=jsonparse path="data,result" data="$(jobRun.requestBody)"]; multiply [type=multiply times="100"]; @@ -198,7 +161,7 @@ observationSource = """ OCRBootstrapSpec = ` type = "bootstrap" -name = "bootstrap" +name = "%s" relay = "evm" schemaVersion = 1 contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" @@ -207,6 +170,27 @@ chainID = 1337 ` ) +func GetOCRBootstrapSpec() string { + return fmt.Sprintf(OCRBootstrapSpec, uuid.New()) +} + +func GetDirectRequestSpec() string { + uuid := uuid.New() + return GetDirectRequestSpecWithUUID(uuid) +} + +func GetDirectRequestSpecWithUUID(u uuid.UUID) string { + return fmt.Sprintf(DirectRequestSpecTemplate, u, u) +} + +func GetOCR2EVMSpecMinimal() string { + return fmt.Sprintf(OCR2EVMSpecMinimalTemplate, uuid.New()) +} + +func GetWebhookSpecNoBody(u uuid.UUID, fetchBridge, submitBridge string) string { + return fmt.Sprintf(WebhookSpecNoBodyTemplate, u, fetchBridge, submitBridge) +} + type KeeperSpecParams struct { Name string ContractAddress string @@ -482,9 +466,9 @@ func (os OCRSpec) Toml() string { } func GenerateOCRSpec(params OCRSpecParams) OCRSpec { - jobID := "123e4567-e89b-12d3-a456-426655440001" - if params.JobID != "" { - jobID = params.JobID + jobID := params.JobID + if jobID == "" { + jobID = uuid.New().String() } transmitterAddress := "0xF67D0290337bca0847005C7ffD1BC75BA9AAE6e4" if params.TransmitterAddress != "" { @@ -494,9 +478,9 @@ func GenerateOCRSpec(params OCRSpecParams) OCRSpec { if params.ContractAddress != "" { contractAddress = params.ContractAddress } - name := "web oracle spec" - if params.Name != "" { - name = params.Name + name := params.Name + if params.Name == "" { + name = jobID } ds1BridgeName := fmt.Sprintf("automatically_generated_bridge_%s", uuid.New().String()) if params.DS1BridgeName != "" { diff --git a/core/testdata/tomlspecs/cron-spec.toml b/core/testdata/tomlspecs/cron-spec.toml deleted file mode 100644 index c4b463acb5f..00000000000 --- a/core/testdata/tomlspecs/cron-spec.toml +++ /dev/null @@ -1,10 +0,0 @@ -type = "cron" -schemaVersion = 1 -schedule = "CRON_TZ=UTC 0 0 1 1 *" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F40" -observationSource = """ -ds [type=http method=GET url="https://chain.link/ETH-USD"]; -ds_parse [type=jsonparse path="data,price"]; -ds_multiply [type=multiply times=100]; -ds -> ds_parse -> ds_multiply; -""" diff --git a/core/testdata/tomlspecs/flux-monitor-spec.toml b/core/testdata/tomlspecs/flux-monitor-spec.toml deleted file mode 100644 index 14bcfb3e19c..00000000000 --- a/core/testdata/tomlspecs/flux-monitor-spec.toml +++ /dev/null @@ -1,28 +0,0 @@ -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F47" -threshold = 0.5 -absoluteThreshold = 0.0 # optional - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "1m" -pollTimerDisabled = false - -observationSource = """ -// data source 1 -ds1 [type=http method=GET url="https://api.coindesk.com/v1/bpi/currentprice.json"]; -jp1 [type=jsonparse path="bpi,USD,rate_float"]; - -// data source 2 -ds2 [type=http method=GET url="https://api.coindesk.com/v1/bpi/currentprice.json"]; -jp2 [type=jsonparse path="bpi,USD,rate_float"]; - -ds1 -> jp1 -> answer1; -ds2 -> jp2 -> answer1; - -answer1 [type=median index=0]; -""" diff --git a/core/testdata/tomlspecs/ocr-spec-local-test.toml b/core/testdata/tomlspecs/ocr-spec-local-test.toml deleted file mode 100644 index 1993d738845..00000000000 --- a/core/testdata/tomlspecs/ocr-spec-local-test.toml +++ /dev/null @@ -1,20 +0,0 @@ -type = "offchainreporting" -schemaVersion = 1 -maxTaskDuration = "10s" -contractAddress = "0x934F3b67915BFbc98d5204122e0BE0ea69F91268" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2BootstrapPeers = [] -isBootstrapPeer = false -monitoringEndpoint = "test:101" -# Below graph will succeed to run through the pipeline -observationSource = """ -// data source 1 -ds1 [type=http method=GET url="https://api.coindesk.com/v1/bpi/currentprice.json"]; -jp [type=jsonparse path="bpi,USD,rate_float"]; -ds1->jp; -""" -keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" -transmitterAddress= "0x2901c8E3BD2D219Ca3c8f4af2f119883b6155219" -p2pPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" diff --git a/core/testdata/tomlspecs/oracle-spec-invalid-key.toml b/core/testdata/tomlspecs/oracle-spec-invalid-key.toml deleted file mode 100644 index fba4b1ba5d3..00000000000 --- a/core/testdata/tomlspecs/oracle-spec-invalid-key.toml +++ /dev/null @@ -1,34 +0,0 @@ -type = "offchainreporting" -schemaVersion = 1 -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F52" -p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -isBootstrapNode = false -keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" -monitoringEndpoint = "chain.link:4321" -transmitterAddress = "0xaA07d525B4006a2f927D79CA78a23A8ee680A32A" -observationTimeout = "10s" -blockchainTimeout = "20s" -contractConfigTrackerSubscribeInterval = "2m" -contractConfigTrackerPollInterval = "1m" -contractConfigConfirmations = 3 -observationSource = """ - // data source 1 - ds1 [type=bridge name=voter_turnout]; - ds1_parse [type=jsonparse path="one,two"]; - ds1_multiply [type=multiply times=1.23]; - - // data source 2 - ds2 [type=http method=GET url="https://chain.link/voter_turnout/USA-2020" requestData="{\\"hi\\": \\"hello\\"}"]; - ds2_parse [type=jsonparse path="three,four"]; - ds2_multiply [type=multiply times=4.56]; - - ds1 -> ds1_parse -> ds1_multiply -> answer1; - ds2 -> ds2_parse -> ds2_multiply -> answer1; - - answer1 [type=median index=0]; - answer2 [type=bridge name=election_winner index=1]; -""" diff --git a/core/testdata/tomlspecs/presumptive-success-job.toml b/core/testdata/tomlspecs/presumptive-success-job.toml deleted file mode 100644 index 7f99ff6abe7..00000000000 --- a/core/testdata/tomlspecs/presumptive-success-job.toml +++ /dev/null @@ -1,13 +0,0 @@ -type = "webhook" -schemaVersion = 1 -externalJobID = "D80D56A0-8E43-4CFA-B7BD-035390F0F54C" -observationSource = """ - fail_but_i_dont_care [type=fail] - succeed1 [type=memo value=10] - succeed2 [type=memo value=5] - final [type=mean] - - fail_but_i_dont_care -> final; - succeed1 -> final; - succeed2 -> final; -""" diff --git a/core/testdata/tomlspecs/vrf-spec.toml b/core/testdata/tomlspecs/vrf-spec.toml deleted file mode 100644 index e44e5154c09..00000000000 --- a/core/testdata/tomlspecs/vrf-spec.toml +++ /dev/null @@ -1,26 +0,0 @@ -type = "vrf" -externalJobID = "123e4567-e89b-12d3-a456-426655440001" -schemaVersion = 1 -name = "vrf-primary" -coordinatorAddress = "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca7" -confirmations = 6 -publicKey = "0x49cf5e2bf04a57620ac3833c998b37e78c0c7ad89b6a9cbc4ce6dba31729930000" -observationSource=""" -decode_log [type=ethabidecodelog - abi="RandomnessRequest(bytes32 keyHash,uint256 seed,bytes32 indexed jobID,address sender,uint256 fee,bytes32 requestID)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] -vrf [type=vrf - publicKey="$(jobSpec.publicKey)" - requestBlockHash="$(jobRun.logBlockHash)" - requestBlockNumber="$(jobRun.logBlockNumber)" - topics="$(jobRun.logTopics)"] -encode_tx [type=ethabiencode - abi="fulfillRandomnessRequest(bytes proof)" - data="{\\"proof\\": $(vrf)}"] -submit_tx [type=ethtx to="0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca7" - data="$(encode_tx)" - minConfirmations="0" - txMeta="{\\"requestTxHash\\": $(jobRun.logTxHash),\\"requestID\\": $(decode_log.requestID),\\"jobID\\": $(jobSpec.databaseID)}"] -decode_log->vrf->encode_tx->submit_tx -""" diff --git a/core/testdata/tomlspecs/vrf-v2-spec.toml b/core/testdata/tomlspecs/vrf-v2-spec.toml deleted file mode 100644 index 46747f7c157..00000000000 --- a/core/testdata/tomlspecs/vrf-v2-spec.toml +++ /dev/null @@ -1,31 +0,0 @@ -type = "vrf" -externalJobID = "123e4567-e89b-12d3-a456-426655440001" -schemaVersion = 1 -name = "vrf-v2-primary" -coordinatorAddress = "0xABA5eDc1a551E55b1A570c0e1f1055e5BE11eca7" -confirmations = 6 -publicKey = "0x49cf5e2bf04a57620ac3833c998b37e78c0c7ad89b6a9cbc4ce6dba31729930000" -pollPeriod = "5s" -observationSource=""" -decode_log [type=ethabidecodelog - abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint64 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,address indexed sender)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] -vrf [type=vrfv2 - publicKey="$(jobSpec.publicKey)" - requestBlockHash="$(jobRun.logBlockHash)" - requestBlockNumber="$(jobRun.logBlockNumber)" - topics="$(jobRun.logTopics)"] -estimate_gas [type=estimategaslimit - to="%s" - multiplier="1.1" - data="$(vrf.output)"] -simulate [type=ethcall - to="%s" - gas="$(estimate_gas)" - gasPrice="$(jobSpec.maxGasPrice)" - extractRevertReason=true - contract="%s" - data="$(vrf.output)"] -decode_log->vrf->estimate_gas->simulate -""" diff --git a/core/utils/config/validate.go b/core/utils/config/validate.go index 858548e3473..32cb94b5205 100644 --- a/core/utils/config/validate.go +++ b/core/utils/config/validate.go @@ -6,8 +6,10 @@ import ( "strconv" "strings" + "github.com/Masterminds/semver/v3" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-relay/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -124,78 +126,37 @@ func NamedMultiErrorList(err error, name string) error { return fmt.Errorf("%s: %s", name, msg) } -type ErrInvalid struct { - Name string - Value any - Msg string -} +type ErrInvalid = config.ErrInvalid // NewErrDuplicate returns an ErrInvalid with a standard duplicate message. func NewErrDuplicate(name string, value any) ErrInvalid { - return ErrInvalid{Name: name, Value: value, Msg: "duplicate - must be unique"} + return config.NewErrDuplicate(name, value) } -func (e ErrInvalid) Error() string { - return fmt.Sprintf("%s: invalid value (%v): %s", e.Name, e.Value, e.Msg) -} +type ErrMissing = config.ErrMissing -type ErrMissing struct { - Name string - Msg string -} +type ErrEmpty = config.ErrEmpty -func (e ErrMissing) Error() string { - return fmt.Sprintf("%s: missing: %s", e.Name, e.Msg) -} +// UniqueStrings is a helper for tracking unique values in string form. +type UniqueStrings = config.UniqueStrings -type ErrEmpty struct { +type ErrOverride struct { Name string - Msg string } -func (e ErrEmpty) Error() string { - return fmt.Sprintf("%s: empty: %s", e.Name, e.Msg) -} - -// UniqueStrings is a helper for tracking unique values in string form. -type UniqueStrings map[string]struct{} - -// IsDupeFmt is like IsDupe, but calls String(). -func (u UniqueStrings) IsDupeFmt(t fmt.Stringer) bool { - if t == nil { - return false - } - if reflect.ValueOf(t).IsNil() { - // interface holds a typed-nil value - return false - } - return u.isDupe(t.String()) +func (e ErrOverride) Error() string { + return fmt.Sprintf("%s: overrides (duplicate keys or list elements) are not allowed for multiple secrets files", e.Name) } -// IsDupe returns true if the set already contains the string, otherwise false. -// Non-nil/empty strings are added to the set. -func (u UniqueStrings) IsDupe(s *string) bool { - if s == nil { - return false - } - return u.isDupe(*s) +type ErrDeprecated struct { + Name string + Version semver.Version } -func (u UniqueStrings) isDupe(s string) bool { - if s == "" { - return false +func (e ErrDeprecated) Error() string { + when := "a future version" + if e.Version != (semver.Version{}) { + when = fmt.Sprintf("version %s", e.Version) } - _, ok := u[s] - if !ok { - u[s] = struct{}{} - } - return ok -} - -type ErrOverride struct { - Name string -} - -func (e ErrOverride) Error() string { - return fmt.Sprintf("%s: overrides (duplicate keys or list elements) are not allowed for multiple secrets files", e.Name) + return fmt.Sprintf("%s: is deprecated and will be removed in %s", e.Name, when) } diff --git a/core/utils/lazy.go b/core/utils/lazy.go index a317d561121..43e84808159 100644 --- a/core/utils/lazy.go +++ b/core/utils/lazy.go @@ -7,8 +7,8 @@ import ( type LazyLoad[T any] struct { f func() (T, error) state T + ok bool lock sync.Mutex - once sync.Once } func NewLazyLoad[T any](f func() (T, error)) *LazyLoad[T] { @@ -21,20 +21,16 @@ func (l *LazyLoad[T]) Get() (out T, err error) { l.lock.Lock() defer l.lock.Unlock() - // fetch only once (or whenever cleared) - l.once.Do(func() { - l.state, err = l.f() - }) - // if err, clear so next get will retry - if err != nil { - l.once = sync.Once{} + if l.ok { + return l.state, nil } - out = l.state - return + l.state, err = l.f() + l.ok = err == nil + return l.state, err } func (l *LazyLoad[T]) Reset() { l.lock.Lock() defer l.lock.Unlock() - l.once = sync.Once{} + l.ok = false } diff --git a/core/utils/mailbox_prom.go b/core/utils/mailbox_prom.go index 30bb707a2b8..0291a51d2c4 100644 --- a/core/utils/mailbox_prom.go +++ b/core/utils/mailbox_prom.go @@ -58,7 +58,7 @@ func (m *MailboxMonitor) Close() error { } func (m *MailboxMonitor) HealthReport() map[string]error { - return map[string]error{m.Name(): m.StartStopOnce.Healthy()} + return map[string]error{m.Name(): m.Healthy()} } func (m *MailboxMonitor) monitorLoop(ctx context.Context, c <-chan time.Time) { diff --git a/core/utils/sleeper_task.go b/core/utils/sleeper_task.go index d020799a9c6..0b45507a82f 100644 --- a/core/utils/sleeper_task.go +++ b/core/utils/sleeper_task.go @@ -19,10 +19,11 @@ type Worker interface { } type sleeperTask struct { - worker Worker - chQueue chan struct{} - chStop chan struct{} - chDone chan struct{} + worker Worker + chQueue chan struct{} + chStop chan struct{} + chDone chan struct{} + chWorkDone chan struct{} StartStopOnce } @@ -36,10 +37,11 @@ type sleeperTask struct { // WakeUp does not block. func NewSleeperTask(worker Worker) SleeperTask { s := &sleeperTask{ - worker: worker, - chQueue: make(chan struct{}, 1), - chStop: make(chan struct{}), - chDone: make(chan struct{}), + worker: worker, + chQueue: make(chan struct{}, 1), + chStop: make(chan struct{}), + chDone: make(chan struct{}), + chWorkDone: make(chan struct{}, 10), } _ = s.StartOnce("SleeperTask-"+worker.Name(), func() error { @@ -83,6 +85,19 @@ func (s *sleeperTask) WakeUp() { } } +func (s *sleeperTask) workDone() { + select { + case s.chWorkDone <- struct{}{}: + default: + } +} + +// WorkDone isn't part of the SleeperTask interface, but can be +// useful in tests to assert that the work has been done. +func (s *sleeperTask) WorkDone() <-chan struct{} { + return s.chWorkDone +} + func (s *sleeperTask) workerLoop() { defer close(s.chDone) @@ -90,6 +105,7 @@ func (s *sleeperTask) workerLoop() { select { case <-s.chQueue: s.worker.Work() + s.workDone() case <-s.chStop: return } diff --git a/core/utils/utils.go b/core/utils/utils.go index 71c65e08c14..d96546b3e19 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -833,6 +833,7 @@ var ( ) // StartStopOnce contains a StartStopOnceState integer +// Deprecated: use services.StateMachine type StartStopOnce struct { state atomic.Int32 sync.RWMutex // lock is held during startup/shutdown, RLock is held while executing functions dependent on a particular state diff --git a/core/web/auth/auth.go b/core/web/auth/auth.go index de6c96b438d..a0a9df58c79 100644 --- a/core/web/auth/auth.go +++ b/core/web/auth/auth.go @@ -79,6 +79,10 @@ func AuthenticateByToken(c *gin.Context, authr Authenticator) error { Secret: c.GetHeader(APISecret), } + if token.AccessKey == "" { + return auth.ErrorAuthFailed + } + // We need to first load the user row so we can compare tokens using the stored salt user, err := authr.FindUserByAPIToken(token.AccessKey) if err != nil { diff --git a/core/web/auth/auth_test.go b/core/web/auth/auth_test.go index ce369fce1b2..896542915ae 100644 --- a/core/web/auth/auth_test.go +++ b/core/web/auth/auth_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -59,7 +60,8 @@ func (u userFindSuccesser) FindUserByAPIToken(token string) (sessions.User, erro func TestAuthenticateByToken_Success(t *testing.T) { user := cltest.MustRandomUser(t) - apiToken := auth.Token{AccessKey: cltest.APIKey, Secret: cltest.APISecret} + key, secret := uuid.New().String(), uuid.New().String() + apiToken := auth.Token{AccessKey: key, Secret: secret} err := user.SetAuthToken(&apiToken) require.NoError(t, err) authr := userFindSuccesser{user: user} @@ -74,8 +76,8 @@ func TestAuthenticateByToken_Success(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) - req.Header.Set(webauth.APIKey, cltest.APIKey) - req.Header.Set(webauth.APISecret, cltest.APISecret) + req.Header.Set(webauth.APIKey, key) + req.Header.Set(webauth.APISecret, secret) router.ServeHTTP(w, req) assert.True(t, called) @@ -95,7 +97,7 @@ func TestAuthenticateByToken_AuthFailed(t *testing.T) { w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) - req.Header.Set(webauth.APIKey, cltest.APIKey) + req.Header.Set(webauth.APIKey, "bad-key") req.Header.Set(webauth.APISecret, "bad-secret") router.ServeHTTP(w, req) @@ -103,6 +105,32 @@ func TestAuthenticateByToken_AuthFailed(t *testing.T) { assert.Equal(t, http.StatusText(http.StatusUnauthorized), http.StatusText(w.Code)) } +func TestAuthenticateByToken_RejectsBlankAccessKey(t *testing.T) { + user := cltest.MustRandomUser(t) + key, secret := "", uuid.New().String() + apiToken := auth.Token{AccessKey: key, Secret: secret} + err := user.SetAuthToken(&apiToken) + require.NoError(t, err) + authr := userFindSuccesser{user: user} + + called := false + router := gin.New() + router.Use(webauth.Authenticate(authr, webauth.AuthenticateByToken)) + router.GET("/", func(c *gin.Context) { + called = true + c.String(http.StatusOK, "") + }) + + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/", nil) + req.Header.Set(webauth.APIKey, key) + req.Header.Set(webauth.APISecret, secret) + router.ServeHTTP(w, req) + + assert.False(t, called) + assert.Equal(t, http.StatusText(http.StatusUnauthorized), http.StatusText(w.Code)) +} + func TestRequireAuth_NoneRequired(t *testing.T) { called := false var authr webauth.Authenticator @@ -307,7 +335,7 @@ func TestRBAC_Routemap_Admin(t *testing.T) { // Assert all admin routes // no endpoint should return StatusUnauthorized - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) for _, route := range routesRolesMap { func() { var resp *http.Response diff --git a/core/web/auth/helpers.go b/core/web/auth/helpers.go index fd81fed2968..8d2984cf742 100644 --- a/core/web/auth/helpers.go +++ b/core/web/auth/helpers.go @@ -2,6 +2,7 @@ package auth import ( "github.com/gin-gonic/gin" + "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) @@ -13,12 +14,12 @@ import ( // so this is ok for now func jsonAPIError(c *gin.Context, statusCode int, err error) { _ = c.Error(err).SetType(gin.ErrorTypePublic) - switch v := err.(type) { - case *models.JSONAPIErrors: - c.JSON(statusCode, v) - default: - c.JSON(statusCode, models.NewJSONAPIErrorsWith(err.Error())) + var jsonErr *models.JSONAPIErrors + if errors.As(err, &jsonErr) { + c.JSON(statusCode, jsonErr) + return } + c.JSON(statusCode, models.NewJSONAPIErrorsWith(err.Error())) } // addForbiddenErrorHeaders adds custom headers to the 403 (Forbidden) response diff --git a/core/web/bridge_types_controller.go b/core/web/bridge_types_controller.go index df22eadde7c..eca99f1a20a 100644 --- a/core/web/bridge_types_controller.go +++ b/core/web/bridge_types_controller.go @@ -83,29 +83,28 @@ func (btc *BridgeTypesController) Create(c *gin.Context) { jsonAPIError(c, http.StatusInternalServerError, e) return } - switch e := err.(type) { - case *pgconn.PgError: + var pgErr *pgconn.PgError + if errors.As(err, &pgErr) { var apiErr error - if e.ConstraintName == "external_initiators_name_key" { + if pgErr.ConstraintName == "external_initiators_name_key" { apiErr = fmt.Errorf("bridge Type %v conflict", bt.Name) } else { apiErr = err } jsonAPIError(c, http.StatusConflict, apiErr) return - default: - resource := presenters.NewBridgeResource(*bt) - resource.IncomingToken = bta.IncomingToken + } + resource := presenters.NewBridgeResource(*bt) + resource.IncomingToken = bta.IncomingToken - btc.App.GetAuditLogger().Audit(audit.BridgeCreated, map[string]interface{}{ - "bridgeName": bta.Name, - "bridgeConfirmations": bta.Confirmations, - "bridgeMinimumContractPayment": bta.MinimumContractPayment, - "bridgeURL": bta.URL, - }) + btc.App.GetAuditLogger().Audit(audit.BridgeCreated, map[string]interface{}{ + "bridgeName": bta.Name, + "bridgeConfirmations": bta.Confirmations, + "bridgeMinimumContractPayment": bta.MinimumContractPayment, + "bridgeURL": bta.URL, + }) - jsonAPIResponse(c, resource, "bridge") - } + jsonAPIResponse(c, resource, "bridge") } // Index lists Bridges, one page at a time. diff --git a/core/web/bridge_types_controller_test.go b/core/web/bridge_types_controller_test.go index 7184b05f5e0..6459cad0545 100644 --- a/core/web/bridge_types_controller_test.go +++ b/core/web/bridge_types_controller_test.go @@ -135,12 +135,12 @@ func TestValidateBridgeNotExist(t *testing.T) { func BenchmarkBridgeTypesController_Index(b *testing.B) { app := cltest.NewApplication(b) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) b.ResetTimer() for n := 0; n < b.N; n++ { resp, cleanup := client.Get("/v2/bridge_types") - defer cleanup() + b.Cleanup(cleanup) assert.Equal(b, http.StatusOK, resp.StatusCode, "Response should be successful") } } @@ -150,7 +150,7 @@ func TestBridgeTypesController_Index(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) bt, err := setupBridgeControllerIndex(t, app.BridgeORM()) assert.NoError(t, err) @@ -218,7 +218,7 @@ func TestBridgeTypesController_Create_Success(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post( "/v2/bridge_types", @@ -246,7 +246,7 @@ func TestBridgeTypesController_Update_Success(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) bridgeName := testutils.RandomizeName("BRidgea") bt := &bridges.BridgeType{ @@ -272,7 +272,7 @@ func TestBridgeController_Show(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) bt := &bridges.BridgeType{ Name: bridges.MustParseBridgeName(testutils.RandomizeName("showbridge")), @@ -302,7 +302,7 @@ func TestBridgeTypesController_Create_AdapterExistsError(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post( "/v2/bridge_types", @@ -318,7 +318,7 @@ func TestBridgeTypesController_Create_BindJSONError(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post( "/v2/bridge_types", @@ -334,7 +334,7 @@ func TestBridgeTypesController_Create_DatabaseError(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post( "/v2/bridge_types", diff --git a/core/web/build_info_controller_test.go b/core/web/build_info_controller_test.go index 9a71951ed3d..e2d2cb0e631 100644 --- a/core/web/build_info_controller_test.go +++ b/core/web/build_info_controller_test.go @@ -18,7 +18,7 @@ func TestBuildInfoController_Show_APICredentials(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/build_info") defer cleanup() diff --git a/core/web/cors_test.go b/core/web/cors_test.go index 120a27c645b..cfd82dd8b71 100644 --- a/core/web/cors_test.go +++ b/core/web/cors_test.go @@ -29,7 +29,7 @@ func TestCors_DefaultOrigins(t *testing.T) { t.Run(test.origin, func(t *testing.T) { app := cltest.NewApplicationWithConfig(t, config) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) headers := map[string]string{"Origin": test.origin} resp, cleanup := client.Get("/v2/chains/evm", headers) @@ -61,7 +61,7 @@ func TestCors_OverrideOrigins(t *testing.T) { }) app := cltest.NewApplicationWithConfig(t, config) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) headers := map[string]string{"Origin": test.origin} resp, cleanup := client.Get("/v2/chains/evm", headers) diff --git a/core/web/cosmos_chains_controller_test.go b/core/web/cosmos_chains_controller_test.go index f443fb64228..f3f5909940f 100644 --- a/core/web/cosmos_chains_controller_test.go +++ b/core/web/cosmos_chains_controller_test.go @@ -185,7 +185,7 @@ func setupCosmosChainsControllerTestV2(t *testing.T, cfgs ...*cosmos.CosmosConfi app := cltest.NewApplicationWithConfig(t, cfg) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return &TestCosmosChainsController{ app: app, diff --git a/core/web/cosmos_keys_controller_test.go b/core/web/cosmos_keys_controller_test.go index 479ee686d57..af421416388 100644 --- a/core/web/cosmos_keys_controller_test.go +++ b/core/web/cosmos_keys_controller_test.go @@ -41,7 +41,7 @@ func TestCosmosKeysController_Create_HappyPath(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) keyStore := app.GetKeyStore() response, cleanup := client.Post("/v2/keys/cosmos", nil) @@ -98,7 +98,7 @@ func setupCosmosKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, key require.NoError(t, app.Start(testutils.Context(t))) require.NoError(t, app.KeyStore.Cosmos().Add(cltest.DefaultCosmosKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/dkgencrypt_keys_controller_test.go b/core/web/dkgencrypt_keys_controller_test.go index 5d8b1ab2328..41d7eb4a752 100644 --- a/core/web/dkgencrypt_keys_controller_test.go +++ b/core/web/dkgencrypt_keys_controller_test.go @@ -103,7 +103,7 @@ func setupDKGEncryptKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, require.NoError(t, app.Start(testutils.Context(t))) require.NoError(t, app.KeyStore.DKGEncrypt().Add(cltest.DefaultDKGEncryptKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/dkgsign_keys_controller_test.go b/core/web/dkgsign_keys_controller_test.go index 0d6d167df99..611c5b3ef0a 100644 --- a/core/web/dkgsign_keys_controller_test.go +++ b/core/web/dkgsign_keys_controller_test.go @@ -103,7 +103,7 @@ func setupDKGSignKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, ke require.NoError(t, app.Start(testutils.Context(t))) require.NoError(t, app.KeyStore.DKGSign().Add(cltest.DefaultDKGSignKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index f708f8634ec..28afe8c43bf 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -277,14 +277,6 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { return } - var nonce int64 = -1 - if nonceStr := c.Query("nextNonce"); nonceStr != "" { - nonce, err = strconv.ParseInt(nonceStr, 10, 64) - if err != nil || nonce < 0 { - jsonAPIError(c, http.StatusBadRequest, errors.Wrapf(err, "invalid value for nonce: expected 0 or positive int, got: %s", nonceStr)) - return - } - } abandon := false if abandonStr := c.Query("abandon"); abandonStr != "" { abandon, err = strconv.ParseBool(abandonStr) @@ -295,13 +287,9 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) { } // Reset the chain - if abandon || nonce >= 0 { + if abandon { var resetErr error - err = chain.TxManager().Reset(func() { - if nonce >= 0 { - resetErr = kst.Reset(address, chain.ID(), nonce) - } - }, address, abandon) + err = chain.TxManager().Reset(address, abandon) err = multierr.Combine(err, resetErr) if err != nil { if strings.Contains(err.Error(), "key state not found with address") { diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index c36ca0aeb5a..98641721737 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -4,7 +4,6 @@ import ( "math/big" "net/http" "net/url" - "strconv" "testing" "github.com/pkg/errors" @@ -32,6 +31,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -41,10 +41,10 @@ func TestETHKeysController_Index_Success(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - k0, addr0 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + k0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) // disabled keys - k1, addr1 := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) - k2, addr2 := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) + k1, addr1 := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) + k2, addr2 := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) expectedKeys := []ethkey.KeyV2{k0, k1, k2} ethClient.On("BalanceAt", mock.Anything, addr0, mock.Anything).Return(big.NewInt(256), nil).Once() @@ -56,7 +56,7 @@ func TestETHKeysController_Index_Success(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/evm") defer cleanup() require.Equal(t, http.StatusOK, resp.StatusCode) @@ -84,23 +84,23 @@ func TestETHKeysController_Index_Errors(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) }) - app := cltest.NewApplicationWithConfig(t, cfg, ethClient) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(nil, errors.New("fake error")).Once() require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") defer cleanup() require.Equal(t, http.StatusOK, resp.StatusCode) @@ -130,11 +130,11 @@ func TestETHKeysController_Index_Disabled(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") defer cleanup() require.Equal(t, http.StatusOK, resp.StatusCode) @@ -156,7 +156,7 @@ func TestETHKeysController_Index_NotDev(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) - + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -169,7 +169,7 @@ func TestETHKeysController_Index_NotDev(t *testing.T) { app := cltest.NewApplicationWithConfigAndKey(t, cfg, ethClient) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") defer cleanup() require.Equal(t, http.StatusOK, resp.StatusCode) @@ -194,7 +194,7 @@ func TestETHKeysController_Index_NoAccounts(t *testing.T) { app := cltest.NewApplication(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/keys/eth") defer cleanup() @@ -224,7 +224,7 @@ func TestETHKeysController_CreateSuccess(t *testing.T) { linkBalance := assets.NewLinkFromJuels(42) ethClient.On("LINKBalance", mock.Anything, mock.Anything, mock.Anything).Return(linkBalance, nil) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) require.NoError(t, app.Start(testutils.Context(t))) @@ -251,6 +251,7 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -259,21 +260,19 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -287,13 +286,13 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) assert.Equal(t, false, updatedKey.Disabled) - assert.Equal(t, int64(nextNonce), updatedKey.NextNonce) } func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -303,14 +302,14 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() @@ -330,7 +329,6 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, true, updatedKey.Disabled) } @@ -347,14 +345,14 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // disabled key - key, addr := cltest.MustInsertRandomDisabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.RandomKey{Disabled: true}.MustInsert(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() @@ -374,7 +372,6 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, false, updatedKey.Disabled) } @@ -382,6 +379,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -391,7 +389,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - key, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("LINKBalance", mock.Anything, addr, mock.Anything).Return(assets.NewLinkFromJuels(1), nil).Once() @@ -402,8 +400,8 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { subject := uuid.New() strategy := commontxmmocks.NewTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{UUID: subject, Valid: true}) - strategy.On("PruneQueue", mock.AnythingOfType("*txmgr.evmTxStore"), mock.AnythingOfType("pg.QOpt")).Return(int64(0), nil) - _, err := chain.TxManager().CreateTransaction(txmgr.TxRequest{ + strategy.On("PruneQueue", mock.Anything, mock.AnythingOfType("*txmgr.evmTxStore")).Return(int64(0), nil) + _, err := chain.TxManager().CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: addr, ToAddress: testutils.NewAddress(), EncodedPayload: []byte{1, 2, 3}, @@ -418,7 +416,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { require.NoError(t, err) assert.Equal(t, 0, count) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() @@ -437,7 +435,6 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.Equal(t, key.ID(), updatedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) - assert.Equal(t, int64(0), updatedKey.NextNonce) assert.Equal(t, false, updatedKey.Disabled) var s string @@ -450,6 +447,7 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -457,20 +455,18 @@ func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) query.Set("abandon", "invalid") chainURL.RawQuery = query.Encode() @@ -484,6 +480,7 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -491,20 +488,18 @@ func TestETHKeysController_ChainFailure_InvalidEnabled(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.KeyStore.Unlock(cltest.Password)) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) query.Set("enabled", "invalid") chainURL.RawQuery = query.Encode() @@ -528,14 +523,12 @@ func TestETHKeysController_ChainFailure_InvalidAddress(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", "invalid address") query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -558,20 +551,18 @@ func TestETHKeysController_ChainFailure_MissingAddress(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", testutils.NewAddress().Hex()) query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) defer cleanup() - assert.Equal(t, http.StatusNotFound, resp.StatusCode) + assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) } func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { @@ -588,14 +579,12 @@ func TestETHKeysController_ChainFailure_InvalidChainID(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", testutils.NewAddress().Hex()) query.Set("evmChainID", "bad chain ID") - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -608,6 +597,7 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -617,18 +607,16 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + _, addr := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} query := chainURL.Query() - nextNonce := 52 query.Set("address", addr.Hex()) query.Set("evmChainID", "123456789") - query.Set("nextNonce", strconv.Itoa(nextNonce)) chainURL.RawQuery = query.Encode() resp, cleanup := client.Post(chainURL.String(), nil) @@ -637,41 +625,10 @@ func TestETHKeysController_ChainFailure_MissingChainID(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } -func TestETHKeysController_ChainFailure_InvalidNonce(t *testing.T) { - t.Parallel() - - ethClient := cltest.NewEthMocksWithStartupAssertions(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].NonceAutoSync = ptr(false) - c.EVM[0].BalanceMonitor.Enabled = ptr(false) - }) - app := cltest.NewApplicationWithConfig(t, cfg, ethClient) - - require.NoError(t, app.KeyStore.Unlock(cltest.Password)) - - // enabled key - _, addr := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) - - require.NoError(t, app.Start(testutils.Context(t))) - - client := app.NewHTTPClient(&cltest.User{}) - chainURL := url.URL{Path: "/v2/keys/evm/chain"} - query := chainURL.Query() - - query.Set("address", addr.Hex()) - query.Set("evmChainID", cltest.FixtureChainID.String()) - query.Set("nextNonce", "bad nonce") - - chainURL.RawQuery = query.Encode() - resp, cleanup := client.Post(chainURL.String(), nil) - defer cleanup() - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) -} - func TestETHKeysController_DeleteSuccess(t *testing.T) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -680,8 +637,8 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { require.NoError(t, app.KeyStore.Unlock(cltest.Password)) // enabled keys - key0, addr0 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) - _, addr1 := cltest.MustInsertRandomEnabledKey(t, app.KeyStore.Eth()) + key0, addr0 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) + _, addr1 := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) ethClient.On("BalanceAt", mock.Anything, addr0, mock.Anything).Return(big.NewInt(1), nil).Once() ethClient.On("BalanceAt", mock.Anything, addr1, mock.Anything).Return(big.NewInt(1), nil).Once() @@ -690,7 +647,7 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/" + addr0.Hex()} resp, cleanup := client.Delete(chainURL.String()) defer cleanup() @@ -704,7 +661,6 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) { assert.Equal(t, key0.ID(), deletedKey.ID) assert.Equal(t, cltest.FixtureChainID.String(), deletedKey.EVMChainID.String()) assert.Equal(t, false, deletedKey.Disabled) - assert.Equal(t, int64(0), deletedKey.NextNonce) resp, cleanup2 := client.Get("/v2/keys/evm") defer cleanup2() @@ -732,7 +688,7 @@ func TestETHKeysController_DeleteFailure_InvalidAddress(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm" + "/bad_address"} resp, cleanup := client.Delete(chainURL.String()) @@ -753,7 +709,7 @@ func TestETHKeysController_DeleteFailure_KeyMissing(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/" + testutils.NewAddress().Hex()} resp, cleanup := client.Delete(chainURL.String()) diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index 02e493a43b2..4ebf06f2b6d 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -204,7 +204,7 @@ func setupEVMChainsControllerTest(t *testing.T, cfg chainlink.GeneralConfig) *Te app := cltest.NewApplicationWithConfig(t, cfg) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return &TestEVMChainsController{ app: app, diff --git a/core/web/evm_forwarders_controller_test.go b/core/web/evm_forwarders_controller_test.go index 8927c014022..46820b42337 100644 --- a/core/web/evm_forwarders_controller_test.go +++ b/core/web/evm_forwarders_controller_test.go @@ -6,7 +6,6 @@ import ( "net/http" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/manyminds/api2go/jsonapi" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -32,7 +31,7 @@ func setupEVMForwardersControllerTest(t *testing.T, overrideFn func(c *chainlink app := cltest.NewApplicationWithConfig(t, configtest.NewGeneralConfig(t, overrideFn)) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return &TestEVMForwardersController{ app: app, @@ -51,7 +50,7 @@ func Test_EVMForwardersController_Track(t *testing.T) { }) // Build EVMForwarderRequest - address := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") + address := utils.RandomAddress() body, err := json.Marshal(web.TrackEVMForwarderRequest{ EVMChainID: chainId, Address: address, @@ -91,11 +90,11 @@ func Test_EVMForwardersController_Index(t *testing.T) { fwdrs := []web.TrackEVMForwarderRequest{ { EVMChainID: chainId, - Address: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81"), + Address: utils.RandomAddress(), }, { EVMChainID: chainId, - Address: common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d82"), + Address: utils.RandomAddress(), }, } for _, fwdr := range fwdrs { diff --git a/core/web/evm_transactions_controller_test.go b/core/web/evm_transactions_controller_test.go index 951d9d99259..9d8336325e2 100644 --- a/core/web/evm_transactions_controller_test.go +++ b/core/web/evm_transactions_controller_test.go @@ -27,8 +27,8 @@ func TestTransactionsController_Index_Success(t *testing.T) { db := app.GetSqlxDB() txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) ethKeyStore := cltest.NewKeyStore(t, db, app.Config.Database()).Eth() - client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, ethKeyStore, 0) + client := app.NewHTTPClient(nil) + _, from := cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) // tx1 tx2 := cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 3, 2, from) // tx2 @@ -69,7 +69,7 @@ func TestTransactionsController_Index_Error(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/transactions?size=TrainingDay") t.Cleanup(cleanup) cltest.AssertServerResponse(t, resp, 422) @@ -82,8 +82,8 @@ func TestTransactionsController_Show_Success(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + client := app.NewHTTPClient(nil) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) tx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, from) require.Len(t, tx.TxAttempts, 1) @@ -115,8 +115,8 @@ func TestTransactionsController_Show_NotFound(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + client := app.NewHTTPClient(nil) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) tx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, from) require.Len(t, tx.TxAttempts, 1) attempt := tx.TxAttempts[0] diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index 69d55b54bba..f5973a20f2f 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -39,13 +39,11 @@ func (tc *EVMTransfersController) Create(c *gin.Context) { } chain, err := getChain(tc.App.GetRelayers().LegacyEVMChains(), tr.EVMChainID.String()) - switch err { - case ErrInvalidChainID, ErrMultipleChains, ErrMissingChainID: - jsonAPIError(c, http.StatusUnprocessableEntity, err) - return - case nil: - break - default: + if err != nil { + if errors.Is(err, ErrInvalidChainID) || errors.Is(err, ErrMultipleChains) || errors.Is(err, ErrMissingChainID) { + jsonAPIError(c, http.StatusUnprocessableEntity, err) + return + } jsonAPIError(c, http.StatusInternalServerError, err) return } @@ -63,7 +61,7 @@ func (tc *EVMTransfersController) Create(c *gin.Context) { } } - etx, err := chain.TxManager().SendNativeToken(chain.ID(), tr.FromAddress, tr.DestinationAddress, *tr.Amount.ToInt(), chain.Config().EVM().GasEstimator().LimitTransfer()) + etx, err := chain.TxManager().SendNativeToken(c, chain.ID(), tr.FromAddress, tr.DestinationAddress, *tr.Amount.ToInt(), chain.Config().EVM().GasEstimator().LimitTransfer()) if err != nil { jsonAPIError(c, http.StatusBadRequest, errors.Errorf("transaction failed: %v", err)) return diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index 8b44b3eb6b6..0f3cdc8bb69 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -45,7 +45,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { app := cltest.NewApplicationWithKey(t, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount, err := assets.NewEthValueS("100") require.NoError(t, err) @@ -87,7 +87,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { app := cltest.NewApplicationWithKey(t, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount := assets.NewEthValue(1000000000000000000) @@ -132,7 +132,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin app := cltest.NewApplicationWithConfigAndKey(t, config, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount, err := assets.NewEthValueS("100") require.NoError(t, err) @@ -167,7 +167,7 @@ func TestTransfersController_TransferZeroAddressError(t *testing.T) { amount, err := assets.NewEthValueS("100") require.NoError(t, err) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) request := models.SendEtherRequest{ DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), FromAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), @@ -197,7 +197,7 @@ func TestTransfersController_TransferBalanceToLowError(t *testing.T) { app := cltest.NewApplicationWithKey(t, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount, err := assets.NewEthValueS("100") require.NoError(t, err) @@ -235,7 +235,7 @@ func TestTransfersController_TransferBalanceToLowError_ZeroBalance(t *testing.T) app := cltest.NewApplicationWithKey(t, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount, err := assets.NewEthValueS("100") require.NoError(t, err) @@ -263,7 +263,7 @@ func TestTransfersController_JSONBindingError(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/transfers", bytes.NewBuffer([]byte(`{"address":""}`))) t.Cleanup(cleanup) @@ -297,7 +297,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { app := cltest.NewApplicationWithConfigAndKey(t, config, ethClient, key) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) amount, err := assets.NewEthValueS("100") require.NoError(t, err) @@ -334,13 +334,13 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { } func TestTransfersController_FindTxAttempt(t *testing.T) { - ctx := testutils.Context(t) tx := txmgr.Tx{ID: 1} attempt := txmgr.TxAttempt{ID: 2} txWithAttempt := txmgr.Tx{ID: 1, TxAttempts: []txmgr.TxAttempt{attempt}} // happy path t.Run("happy_path", func(t *testing.T) { + ctx := testutils.Context(t) timeout := 5 * time.Second var done bool find := func(_ int64) (txmgr.Tx, error) { @@ -358,6 +358,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // failed to find tx t.Run("failed to find tx", func(t *testing.T) { + ctx := testutils.Context(t) find := func(_ int64) (txmgr.Tx, error) { return txmgr.Tx{}, fmt.Errorf("ERRORED") } @@ -367,6 +368,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // timeout t.Run("timeout", func(t *testing.T) { + ctx := testutils.Context(t) find := func(_ int64) (txmgr.Tx, error) { return tx, nil } @@ -376,6 +378,7 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { // context canceled t.Run("context canceled", func(t *testing.T) { + ctx := testutils.Context(t) find := func(_ int64) (txmgr.Tx, error) { return tx, nil } diff --git a/core/web/evm_tx_attempts_controller_test.go b/core/web/evm_tx_attempts_controller_test.go index abf80add213..6c073b3ac41 100644 --- a/core/web/evm_tx_attempts_controller_test.go +++ b/core/web/evm_tx_attempts_controller_test.go @@ -21,9 +21,9 @@ func TestTxAttemptsController_Index_Success(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) txStore := cltest.NewTestTxStore(t, app.GetSqlxDB(), app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) - _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth(), 0) + _, from := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 1, from) cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 1, 2, from) @@ -51,7 +51,7 @@ func TestTxAttemptsController_Index_Error(t *testing.T) { app := cltest.NewApplicationWithKey(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/tx_attempts?size=TrainingDay") t.Cleanup(cleanup) cltest.AssertServerResponse(t, resp, 422) diff --git a/core/web/external_initiators_controller_test.go b/core/web/external_initiators_controller_test.go index bc7d46a4f91..2229b40b7ef 100644 --- a/core/web/external_initiators_controller_test.go +++ b/core/web/external_initiators_controller_test.go @@ -74,7 +74,7 @@ func TestExternalInitiatorsController_Index(t *testing.T) { })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) db := app.GetSqlxDB() borm := bridges.NewORM(db, logger.TestLogger(t), app.GetConfig().Database()) @@ -140,7 +140,7 @@ func TestExternalInitiatorsController_Create_success(t *testing.T) { })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/external_initiators", bytes.NewBufferString(`{"name":"bitcoin","url":"http://without.a.name"}`), @@ -168,7 +168,7 @@ func TestExternalInitiatorsController_Create_without_URL(t *testing.T) { })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/external_initiators", bytes.NewBufferString(`{"name":"no-url"}`), @@ -196,7 +196,7 @@ func TestExternalInitiatorsController_Create_invalid(t *testing.T) { })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/external_initiators", bytes.NewBufferString(`{"url":"http://without.a.name"}`), @@ -220,7 +220,7 @@ func TestExternalInitiatorsController_Delete(t *testing.T) { err := app.BridgeORM().CreateExternalInitiator(&exi) require.NoError(t, err) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Delete("/v2/external_initiators/" + exi.Name) t.Cleanup(cleanup) @@ -236,7 +236,7 @@ func TestExternalInitiatorsController_DeleteNotFound(t *testing.T) { })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) tests := []struct { Name string diff --git a/core/web/features_controller_test.go b/core/web/features_controller_test.go index 33520093347..8ef2e08d394 100644 --- a/core/web/features_controller_test.go +++ b/core/web/features_controller_test.go @@ -21,7 +21,7 @@ func Test_FeaturesController_List(t *testing.T) { c.Feature.UICSAKeys = &csa })) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/features") t.Cleanup(cleanup) diff --git a/core/web/health_controller.go b/core/web/health_controller.go index 3646331bb82..d6a7edb2340 100644 --- a/core/web/health_controller.go +++ b/core/web/health_controller.go @@ -5,7 +5,6 @@ import ( "github.com/gin-gonic/gin" - "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -14,6 +13,11 @@ type HealthController struct { App chainlink.Application } +const ( + HealthStatusPassing = "passing" + HealthStatusFailing = "failing" +) + // NOTE: We only implement the k8s readiness check, *not* the liveness check. Liveness checks are only recommended in cases // where the app doesn't crash itself on panic, and if implemented incorrectly can cause cascading failures. // See the following for more information: @@ -38,11 +42,11 @@ func (hc *HealthController) Readyz(c *gin.Context) { checks := make([]presenters.Check, 0, len(errors)) for name, err := range errors { - status := services.StatusPassing + status := HealthStatusPassing var output string if err != nil { - status = services.StatusFailing + status = HealthStatusFailing output = err.Error() } @@ -74,11 +78,11 @@ func (hc *HealthController) Health(c *gin.Context) { checks := make([]presenters.Check, 0, len(errors)) for name, err := range errors { - status := services.StatusPassing + status := HealthStatusPassing var output string if err != nil { - status = services.StatusFailing + status = HealthStatusFailing output = err.Error() } diff --git a/core/web/health_controller_test.go b/core/web/health_controller_test.go index 5f915dfedce..d380b279d00 100644 --- a/core/web/health_controller_test.go +++ b/core/web/health_controller_test.go @@ -40,7 +40,7 @@ func TestHealthController_Readyz(t *testing.T) { app.HealthChecker = healthChecker require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/readyz") t.Cleanup(cleanup) assert.Equal(t, tc.status, resp.StatusCode) diff --git a/core/web/helpers.go b/core/web/helpers.go index 5339027ac29..e8900522eb9 100644 --- a/core/web/helpers.go +++ b/core/web/helpers.go @@ -20,12 +20,12 @@ import ( // the JSON value of errors. func jsonAPIError(c *gin.Context, statusCode int, err error) { _ = c.Error(err).SetType(gin.ErrorTypePublic) - switch v := err.(type) { - case *models.JSONAPIErrors: - c.JSON(statusCode, v) - default: - c.JSON(statusCode, models.NewJSONAPIErrorsWith(err.Error())) + var jsonErr *models.JSONAPIErrors + if errors.As(err, &jsonErr) { + c.JSON(statusCode, jsonErr) + return } + c.JSON(statusCode, models.NewJSONAPIErrorsWith(err.Error())) } func paginatedResponse( diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index f18fcdd8c29..345662909a4 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -2,6 +2,7 @@ package web_test import ( "bytes" + _ "embed" "encoding/hex" "encoding/json" "fmt" @@ -17,10 +18,11 @@ import ( "github.com/google/uuid" p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pelletier/go-toml" - "github.com/smartcontractkit/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -142,18 +144,21 @@ func TestJobController_Create_HappyPath(t *testing.T) { jorm := app.JobORM() var tt = []struct { - name string - toml string - assertion func(t *testing.T, r *http.Response) + name string + tomlTemplate func(nameAndExternalJobID string) string + assertion func(t *testing.T, nameAndExternalJobID string, r *http.Response) }{ { name: "offchain reporting", - toml: testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ - TransmitterAddress: app.Keys[0].Address.Hex(), - DS1BridgeName: b1, - DS2BridgeName: b2, - }).Toml(), - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ + TransmitterAddress: app.Keys[0].Address.Hex(), + DS1BridgeName: b1, + DS2BridgeName: b2, + Name: nameAndExternalJobID, + }).Toml() + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resource := presenters.JobResource{} @@ -164,7 +169,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.NoError(t, err) require.NotNil(t, resource.OffChainReportingSpec) - assert.Equal(t, "web oracle spec", jb.Name.ValueOrZero()) + assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.Equal(t, jb.OCROracleSpec.P2PBootstrapPeers, resource.OffChainReportingSpec.P2PBootstrapPeers) assert.Equal(t, jb.OCROracleSpec.IsBootstrapPeer, resource.OffChainReportingSpec.IsBootstrapPeer) assert.Equal(t, jb.OCROracleSpec.EncryptedOCRKeyBundleID, resource.OffChainReportingSpec.EncryptedOCRKeyBundleID) @@ -181,17 +186,19 @@ func TestJobController_Create_HappyPath(t *testing.T) { }, { name: "keeper", - toml: ` + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(` type = "keeper" schemaVersion = 1 - name = "example keeper spec" + name = "%s" contractAddress = "0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba" fromAddress = "0xa8037A20989AFcBC51798de9762b351D63ff462e" evmChainID = 0 minIncomingConfigurations = 1 - externalJobID = "123e4567-e89b-12d3-a456-426655440002" - `, - assertion: func(t *testing.T, r *http.Response) { + externalJobID = "%s" + `, nameAndExternalJobID, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusInternalServerError, r.StatusCode) errs := cltest.ParseJSONAPIErrors(t, r.Body) @@ -200,13 +207,13 @@ func TestJobController_Create_HappyPath(t *testing.T) { // services failed to start require.Contains(t, errs.Errors[0].Detail, "no contract code at given address") // but the job should still exist - jb, err := jorm.FindJobByExternalJobID(uuid.MustParse(("123e4567-e89b-12d3-a456-426655440002"))) + jb, err := jorm.FindJobByExternalJobID(uuid.MustParse(nameAndExternalJobID)) require.NoError(t, err) require.NotNil(t, jb.KeeperSpec) require.Equal(t, ethkey.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) require.Equal(t, ethkey.EIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e"), jb.KeeperSpec.FromAddress) - assert.Equal(t, "example keeper spec", jb.Name.ValueOrZero()) + assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) // Sanity check to make sure it inserted correctly require.Equal(t, ethkey.EIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba"), jb.KeeperSpec.ContractAddress) @@ -215,8 +222,10 @@ func TestJobController_Create_HappyPath(t *testing.T) { }, { name: "cron", - toml: testspecs.CronSpec, - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(testspecs.CronSpecTemplate, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resource := presenters.JobResource{} err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) @@ -232,8 +241,10 @@ func TestJobController_Create_HappyPath(t *testing.T) { }, { name: "cron-dot-separator", - toml: testspecs.CronSpecDotSep, - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(testspecs.CronSpecDotSepTemplate, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resource := presenters.JobResource{} err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) @@ -249,8 +260,10 @@ func TestJobController_Create_HappyPath(t *testing.T) { }, { name: "directrequest", - toml: testspecs.DirectRequestSpec, - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return testspecs.GetDirectRequestSpecWithUUID(uuid.MustParse(nameAndExternalJobID)) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resource := presenters.JobResource{} err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) @@ -260,17 +273,19 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.NoError(t, err) require.NotNil(t, jb.DirectRequestSpec) - assert.Equal(t, "example eth request event spec", jb.Name.ValueOrZero()) + assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.NotNil(t, resource.PipelineSpec.DotDAGSource) // Sanity check to make sure it inserted correctly require.Equal(t, ethkey.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.DirectRequestSpec.ContractAddress) - require.NotZero(t, jb.ExternalJobID[:]) + require.Equal(t, jb.ExternalJobID.String(), nameAndExternalJobID) }, }, { name: "directrequest-with-requesters-and-min-contract-payment", - toml: testspecs.DirectRequestSpecWithRequestersAndMinContractPayment, - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(testspecs.DirectRequestSpecWithRequestersAndMinContractPaymentTemplate, nameAndExternalJobID, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resource := presenters.JobResource{} err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) @@ -280,20 +295,22 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.NoError(t, err) require.NotNil(t, jb.DirectRequestSpec) - assert.Equal(t, "example eth request event spec with requesters and min contract payment", jb.Name.ValueOrZero()) + assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.NotNil(t, resource.PipelineSpec.DotDAGSource) assert.NotNil(t, resource.DirectRequestSpec.Requesters) assert.Equal(t, "1000000000000000000000", resource.DirectRequestSpec.MinContractPayment.String()) // Check requesters got saved properly require.EqualValues(t, []common.Address{common.HexToAddress("0xAaAA1F8ee20f5565510b84f9353F1E333e753B7a"), common.HexToAddress("0xBbBb70f0E81c6F3430dfDc9fa02fB22bDD818c4E")}, jb.DirectRequestSpec.Requesters) require.Equal(t, "1000000000000000000000", jb.DirectRequestSpec.MinContractPayment.String()) - require.NotZero(t, jb.ExternalJobID[:]) + require.Equal(t, jb.ExternalJobID.String(), nameAndExternalJobID) }, }, { name: "fluxmonitor", - toml: testspecs.FluxMonitorSpec, - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(nameAndExternalJobID string) string { + return fmt.Sprintf(testspecs.FluxMonitorSpecTemplate, nameAndExternalJobID, nameAndExternalJobID) + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusInternalServerError, r.StatusCode) @@ -303,11 +320,11 @@ func TestJobController_Create_HappyPath(t *testing.T) { // services failed to start require.Contains(t, errs.Errors[0].Detail, "no contract code at given address") // but the job should still exist - jb, err := jorm.FindJobByExternalJobID(uuid.MustParse(("123e4567-e89b-12d3-a456-426655440005"))) + jb, err := jorm.FindJobByExternalJobID(uuid.MustParse(nameAndExternalJobID)) require.NoError(t, err) require.NotNil(t, jb.FluxMonitorSpec) - assert.Equal(t, "example flux monitor spec", jb.Name.ValueOrZero()) + assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) assert.NotNil(t, jb.PipelineSpec.DotDagSource) assert.Equal(t, ethkey.EIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42"), jb.FluxMonitorSpec.ContractAddress) assert.Equal(t, time.Second, jb.FluxMonitorSpec.IdleTimerPeriod) @@ -318,8 +335,10 @@ func TestJobController_Create_HappyPath(t *testing.T) { }, { name: "vrf", - toml: testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: pks[0].PublicKey.String()}).Toml(), - assertion: func(t *testing.T, r *http.Response) { + tomlTemplate: func(_ string) string { + return testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{PublicKey: pks[0].PublicKey.String()}).Toml() + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { require.Equal(t, http.StatusOK, r.StatusCode) resp := cltest.ParseResponseBody(t, r) resource := presenters.JobResource{} @@ -341,13 +360,15 @@ func TestJobController_Create_HappyPath(t *testing.T) { for _, tc := range tt { c := tc t.Run(c.name, func(t *testing.T) { + nameAndExternalJobID := uuid.New().String() + toml := c.tomlTemplate(nameAndExternalJobID) body, err := json.Marshal(web.CreateJobRequest{ - TOML: c.toml, + TOML: toml, }) require.NoError(t, err) response, cleanup := client.Post("/v2/jobs", bytes.NewReader(body)) defer cleanup() - c.assertion(t, response) + c.assertion(t, nameAndExternalJobID, response) }) } } @@ -359,9 +380,9 @@ func TestJobsController_Create_WebhookSpec(t *testing.T) { _, fetchBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, submitBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) - tomlStr := fmt.Sprintf(testspecs.WebhookSpecNoBody, fetchBridge.Name.String(), submitBridge.Name.String()) + tomlStr := testspecs.GetWebhookSpecNoBody(uuid.New(), fetchBridge.Name.String(), submitBridge.Name.String()) body, _ := json.Marshal(web.CreateJobRequest{ TOML: tomlStr, }) @@ -378,16 +399,21 @@ func TestJobsController_Create_WebhookSpec(t *testing.T) { require.NoError(t, err) } +//go:embed webhook-spec-template.yml +var webhookSpecTemplate string + func TestJobsController_FailToCreate_EmptyJsonAttribute(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) - tomlBytes := cltest.MustReadFile(t, "../testdata/tomlspecs/webhook-job-spec-with-empty-json.toml") - body, _ := json.Marshal(web.CreateJobRequest{ - TOML: string(tomlBytes), + nameAndExternalJobID := uuid.New() + spec := fmt.Sprintf(webhookSpecTemplate, nameAndExternalJobID, nameAndExternalJobID) + body, err := json.Marshal(web.CreateJobRequest{ + TOML: spec, }) + require.NoError(t, err) response, cleanup := client.Post("/v2/jobs", bytes.NewReader(body)) defer cleanup() @@ -493,7 +519,7 @@ func TestJobsController_Update_HappyPath(t *testing.T) { _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) var jb job.Job ocrspec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ @@ -555,7 +581,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) var jb job.Job ocrspec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{ @@ -635,7 +661,7 @@ func setupJobsControllerTests(t *testing.T) (ta *cltest.TestApplication, cc clte app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) vrfKeyStore := app.GetKeyStore().VRF() _, err := vrfKeyStore.Create() require.NoError(t, err) @@ -656,7 +682,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) var jb job.Job ocrspec := testspecs.GenerateOCRSpec(testspecs.OCRSpecParams{DS1BridgeName: bridge.Name.String(), DS2BridgeName: bridge2.Name.String(), EVMChainID: testutils.FixtureChainID.String()}) @@ -670,7 +696,23 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication err = app.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) - erejb, err := directrequest.ValidatedDirectRequestSpec(string(cltest.MustReadFile(t, "../testdata/tomlspecs/direct-request-spec.toml"))) + drSpec := fmt.Sprintf(` + type = "directrequest" + schemaVersion = 1 + evmChainID = "0" + name = "example eth request event spec" + contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" + externalJobID = "%s" + observationSource = """ + ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; + ds1_merge [type=merge left="{}"] + ds1_parse [type=jsonparse path="USD"]; + ds1_multiply [type=multiply times=100]; + ds1 -> ds1_parse -> ds1_multiply; + """ + `, uuid.New()) + + erejb, err := directrequest.ValidatedDirectRequestSpec(drSpec) require.NoError(t, err) err = app.AddJobV2(testutils.Context(t), &erejb) require.NoError(t, err) diff --git a/core/web/log_controller_test.go b/core/web/log_controller_test.go index 029dc4e8d3f..e4cd1768cef 100644 --- a/core/web/log_controller_test.go +++ b/core/web/log_controller_test.go @@ -41,7 +41,7 @@ func TestLogController_GetLogConfig(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, err := client.HTTPClient.Get("/v2/log") require.NoError(t, err) @@ -112,7 +112,7 @@ func TestLogController_PatchLogConfig(t *testing.T) { t.Run(tc.Description, func(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) request := web.LogPatchRequest{Level: tc.logLevel, SqlEnabled: tc.logSql} diff --git a/core/web/loop_registry.go b/core/web/loop_registry.go index 345ff03704e..b94778675e0 100644 --- a/core/web/loop_registry.go +++ b/core/web/loop_registry.go @@ -85,7 +85,7 @@ func metricTarget(hostName string, port int, path string) *targetgroup.Group { } } -// pluginMetricHandlers routes from endpoints published in service discovery to the the backing LOOP endpoint +// pluginMetricHandlers routes from endpoints published in service discovery to the backing LOOP endpoint func (l *LoopRegistryServer) pluginMetricHandler(gc *gin.Context) { pluginName := gc.Param("name") p, ok := l.registry.Get(pluginName) @@ -95,7 +95,7 @@ func (l *LoopRegistryServer) pluginMetricHandler(gc *gin.Context) { } // unlike discovery, this endpoint is internal btw the node and plugin - pluginURL := fmt.Sprintf("http://%s:%d/metrics", l.loopHostName, p.EnvCfg.PrometheusPort()) + pluginURL := fmt.Sprintf("http://%s:%d/metrics", l.loopHostName, p.EnvCfg.PrometheusPort) res, err := l.client.Get(pluginURL) //nolint if err != nil { msg := fmt.Sprintf("plugin metric handler failed to get plugin url %s", html.EscapeString(pluginURL)) diff --git a/core/web/loop_registry_internal_test.go b/core/web/loop_registry_internal_test.go index de2b93c5b6b..48cd75a5cff 100644 --- a/core/web/loop_registry_internal_test.go +++ b/core/web/loop_registry_internal_test.go @@ -38,7 +38,7 @@ func TestLoopRegistryServer_CantWriteToResponse(t *testing.T) { l, o := logger.TestLoggerObserved(t, zap.ErrorLevel) s := &LoopRegistryServer{ exposedPromPort: 1, - registry: plugins.NewLoopRegistry(l), + registry: plugins.NewLoopRegistry(l, nil), logger: l.(logger.SugaredLogger), jsonMarshalFn: json.Marshal, } @@ -53,7 +53,7 @@ func TestLoopRegistryServer_CantMarshal(t *testing.T) { l, o := logger.TestLoggerObserved(t, zap.ErrorLevel) s := &LoopRegistryServer{ exposedPromPort: 1, - registry: plugins.NewLoopRegistry(l), + registry: plugins.NewLoopRegistry(l, nil), logger: l.(logger.SugaredLogger), jsonMarshalFn: func(any) ([]byte, error) { return []byte(""), errors.New("can't unmarshal") diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 848579214f3..59a4d0df686 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -14,17 +14,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/plugins" ) type mockLoopImpl struct { t *testing.T - *plugins.PromServer + *loop.PromServer } // test prom var to avoid collision with real chainlink metrics @@ -44,7 +44,7 @@ func configurePromRegistry() { func newMockLoopImpl(t *testing.T, port int) *mockLoopImpl { return &mockLoopImpl{ t: t, - PromServer: plugins.NewPromServer(port, logger.TestLogger(t).Named("mock-loop"), plugins.WithHandler(testHandler)), + PromServer: loop.PromServerOpts{Handler: testHandler}.New(port, logger.TestLogger(t).Named("mock-loop")), } } @@ -91,12 +91,12 @@ func TestLoopRegistry(t *testing.T) { // set up a test prometheus registry and test metric that is used by // our mock loop impl and isolated from the default prom register configurePromRegistry() - mockLoop := newMockLoopImpl(t, loop.EnvCfg.PrometheusPort()) + mockLoop := newMockLoopImpl(t, loop.EnvCfg.PrometheusPort) mockLoop.start() defer mockLoop.close() mockLoop.run() - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) t.Run("discovery endpoint", func(t *testing.T) { // under the covers this is routing thru the app into loop registry diff --git a/core/web/nodes_controller.go b/core/web/nodes_controller.go index 1eddc67c364..3547b150bc7 100644 --- a/core/web/nodes_controller.go +++ b/core/web/nodes_controller.go @@ -76,9 +76,9 @@ func (n *nodesController[R]) Index(c *gin.Context, size, page, offset int) { // fetch nodes for chain ID // backward compatibility var rid relay.ID - err := rid.UnmarshalString(id) + err = rid.UnmarshalString(id) if err != nil { - rid.ChainID = relay.ChainID(id) + rid.ChainID = id rid.Network = n.nodeSet.network } nodes, count, err = n.nodeSet.NodeStatuses(c, offset, size, rid) diff --git a/core/web/ocr2_keys_controller_test.go b/core/web/ocr2_keys_controller_test.go index f69ed41f9dd..c7549cd2da5 100644 --- a/core/web/ocr2_keys_controller_test.go +++ b/core/web/ocr2_keys_controller_test.go @@ -101,7 +101,7 @@ func setupOCR2KeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keyst app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) require.NoError(t, app.KeyStore.OCR2().Add(cltest.DefaultOCR2Key)) diff --git a/core/web/ocr_keys_controller_test.go b/core/web/ocr_keys_controller_test.go index 911947fcb72..ebb671bc1e2 100644 --- a/core/web/ocr_keys_controller_test.go +++ b/core/web/ocr_keys_controller_test.go @@ -89,7 +89,7 @@ func setupOCRKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keysto app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) diff --git a/core/web/p2p_keys_controller_test.go b/core/web/p2p_keys_controller_test.go index 4df5f4d91b2..af15e21a0f6 100644 --- a/core/web/p2p_keys_controller_test.go +++ b/core/web/p2p_keys_controller_test.go @@ -43,7 +43,7 @@ func TestP2PKeysController_Create_HappyPath(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) keyStore := app.GetKeyStore() response, cleanup := client.Post("/v2/keys/p2p", nil) @@ -115,7 +115,7 @@ func setupP2PKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, keysto require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, app.KeyStore.P2P().Add(cltest.DefaultP2PKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/ping_controller_test.go b/core/web/ping_controller_test.go index 0040f7dfdad..8e1862cd8c7 100644 --- a/core/web/ping_controller_test.go +++ b/core/web/ping_controller_test.go @@ -5,6 +5,8 @@ import ( "strings" "testing" + "github.com/google/uuid" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -22,7 +24,7 @@ func TestPingController_Show_APICredentials(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Get("/v2/ping") defer cleanup() @@ -43,7 +45,7 @@ func TestPingController_Show_ExternalInitiatorCredentials(t *testing.T) { } eir_url := cltest.WebURL(t, "http://localhost:8888") eir := &bridges.ExternalInitiatorRequest{ - Name: "bitcoin", + Name: uuid.New().String(), URL: &eir_url, } diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index 8e53384856d..5b17fcb007e 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -14,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -51,16 +52,14 @@ func TestPipelineRunsController_CreateWithBody_HappyPath(t *testing.T) { _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{URL: mockServer.URL}, app.GetConfig().Database()) // Add the job - var uuid uuid.UUID + uuid := uuid.New() { - tomlStr := fmt.Sprintf(testspecs.WebhookSpecWithBody, bridge.Name.String()) + tomlStr := fmt.Sprintf(testspecs.WebhookSpecWithBodyTemplate, uuid, bridge.Name.String()) jb, err := webhook.ValidatedWebhookSpec(tomlStr, app.GetExternalInitiatorManager()) require.NoError(t, err) err = app.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) - - uuid = jb.ExternalJobID } // Give the job.Spawner ample time to discover the job and start its service @@ -69,7 +68,7 @@ func TestPipelineRunsController_CreateWithBody_HappyPath(t *testing.T) { // Make the request { - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) body := strings.NewReader(`{"data":{"result":"123.45"}}`) response, cleanup := client.Post("/v2/jobs/"+uuid.String()+"/runs", body) defer cleanup() @@ -112,16 +111,14 @@ func TestPipelineRunsController_CreateNoBody_HappyPath(t *testing.T) { _, submitBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{URL: mockServer.URL}, app.GetConfig().Database()) // Add the job - var uuid uuid.UUID + uuid := uuid.New() { - tomlStr := fmt.Sprintf(testspecs.WebhookSpecNoBody, bridge.Name.String(), submitBridge.Name.String()) + tomlStr := testspecs.GetWebhookSpecNoBody(uuid, bridge.Name.String(), submitBridge.Name.String()) jb, err := webhook.ValidatedWebhookSpec(tomlStr, app.GetExternalInitiatorManager()) require.NoError(t, err) err = app.AddJobV2(testutils.Context(t), &jb) require.NoError(t, err) - - uuid = jb.ExternalJobID } // Give the job.Spawner ample time to discover the job and start its service @@ -130,7 +127,7 @@ func TestPipelineRunsController_CreateNoBody_HappyPath(t *testing.T) { // Make the request (authorized as user) { - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) response, cleanup := client.Post("/v2/jobs/"+uuid.String()+"/runs", nil) defer cleanup() cltest.AssertServerResponse(t, response, http.StatusOK) @@ -243,7 +240,7 @@ func TestPipelineRunsController_ShowRun_InvalidID(t *testing.T) { t.Parallel() app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) response, cleanup := client.Get("/v2/jobs/1/runs/invalid-run-ID") defer cleanup() @@ -253,6 +250,7 @@ func TestPipelineRunsController_ShowRun_InvalidID(t *testing.T) { func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, int32, []int64) { t.Parallel() ethClient := cltest.NewEthMocksWithStartupAssertions(t) + ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) c.P2P.V1.Enabled = ptr(true) @@ -263,14 +261,16 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i app := cltest.NewApplicationWithConfigAndKey(t, cfg, ethClient, cltest.DefaultP2PKey) require.NoError(t, app.Start(testutils.Context(t))) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) key, _ := cltest.MustInsertRandomKey(t, app.KeyStore.Eth()) + nameAndExternalJobID := uuid.New() sp := fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 - externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46" + externalJobID = "%s" + name = "%s" contractAddress = "%s" evmChainID = "0" p2pBootstrapPeers = [ @@ -297,7 +297,7 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i answer [type=median index=0]; """ - `, testutils.NewAddress().Hex(), cltest.DefaultOCRKeyBundleID, key.Address.Hex()) + `, nameAndExternalJobID, nameAndExternalJobID, testutils.NewAddress().Hex(), cltest.DefaultOCRKeyBundleID, key.Address.Hex()) var jb job.Job err := toml.Unmarshal([]byte(sp), &jb) require.NoError(t, err) diff --git a/core/web/presenters/check.go b/core/web/presenters/check.go index 4ee6051727e..52e4aa68005 100644 --- a/core/web/presenters/check.go +++ b/core/web/presenters/check.go @@ -1,14 +1,10 @@ package presenters -import ( - "github.com/smartcontractkit/chainlink/v2/core/services" -) - type Check struct { JAID - Name string `json:"name"` - Status services.Status `json:"status"` - Output string `json:"output"` + Name string `json:"name"` + Status string `json:"status"` + Output string `json:"output"` } func (c Check) GetName() string { diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index d3a8c55c2be..167679513ef 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -14,7 +14,6 @@ type ETHKeyResource struct { JAID EVMChainID utils.Big `json:"evmChainID"` Address string `json:"address"` - NextNonce int64 `json:"nextNonce"` EthBalance *assets.Eth `json:"ethBalance"` LinkBalance *assets.Link `json:"linkBalance"` Disabled bool `json:"disabled"` @@ -42,7 +41,6 @@ func NewETHKeyResource(k ethkey.KeyV2, state ethkey.State, opts ...NewETHKeyOpti r := ÐKeyResource{ JAID: NewJAID(k.Address.Hex()), EVMChainID: state.EVMChainID, - NextNonce: state.NextNonce, Address: k.Address.Hex(), EthBalance: nil, LinkBalance: nil, diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 1518762cc0e..7afb55068fb 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -31,7 +31,6 @@ func TestETHKeyResource(t *testing.T) { state := ethkey.State{ ID: 1, EVMChainID: *utils.NewBigI(42), - NextNonce: 99, Address: eip55address, CreatedAt: now, UpdatedAt: now, @@ -59,7 +58,6 @@ func TestETHKeyResource(t *testing.T) { "attributes":{ "address":"%s", "evmChainID":"42", - "nextNonce": 99, "ethBalance":"1", "linkBalance":"1", "disabled":true, @@ -89,7 +87,6 @@ func TestETHKeyResource(t *testing.T) { "attributes":{ "address":"%s", "evmChainID":"42", - "nextNonce": 99, "ethBalance":null, "linkBalance":null, "disabled":true, diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index b1f42ebc68f..2aa97730881 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -525,6 +525,8 @@ func NewJobResource(j job.Job) *JobResource { resource.BootstrapSpec = NewBootstrapSpec(j.BootstrapSpec) case job.Gateway: resource.GatewaySpec = NewGatewaySpec(j.GatewaySpec) + case job.LegacyGasStationServer, job.LegacyGasStationSidecar: + // unsupported } jes := []JobError{} diff --git a/core/web/presenters/p2p_key_test.go b/core/web/presenters/p2p_key_test.go index c78328a81d4..2d30f87fe18 100644 --- a/core/web/presenters/p2p_key_test.go +++ b/core/web/presenters/p2p_key_test.go @@ -9,12 +9,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" ) func TestP2PKeyResource(t *testing.T) { - key, err := p2pkey.NewV2() - require.NoError(t, err) + key := keystest.NewP2PKeyV2(t) peerID := key.PeerID() peerIDStr := peerID.String() pubKey := key.GetPublic() diff --git a/core/web/replay_controller.go b/core/web/replay_controller.go index 47c3e2dc522..5006b68c845 100644 --- a/core/web/replay_controller.go +++ b/core/web/replay_controller.go @@ -47,13 +47,11 @@ func (bdc *ReplayController) ReplayFromBlock(c *gin.Context) { } chain, err := getChain(bdc.App.GetRelayers().LegacyEVMChains(), c.Query("evmChainID")) - switch err { - case ErrInvalidChainID, ErrMultipleChains, ErrMissingChainID: - jsonAPIError(c, http.StatusUnprocessableEntity, err) - return - case nil: - break - default: + if err != nil { + if errors.Is(err, ErrInvalidChainID) || errors.Is(err, ErrMultipleChains) || errors.Is(err, ErrMissingChainID) { + jsonAPIError(c, http.StatusUnprocessableEntity, err) + return + } jsonAPIError(c, http.StatusInternalServerError, err) return } diff --git a/core/web/resolver/chain.go b/core/web/resolver/chain.go index 02573f423a4..53f1016d72b 100644 --- a/core/web/resolver/chain.go +++ b/core/web/resolver/chain.go @@ -2,6 +2,7 @@ package resolver import ( "github.com/graph-gophers/graphql-go" + "github.com/smartcontractkit/chainlink-relay/pkg/types" ) diff --git a/core/web/resolver/job_test.go b/core/web/resolver/job_test.go index 7d73d7d0d2a..e91e37b6903 100644 --- a/core/web/resolver/job_test.go +++ b/core/web/resolver/job_test.go @@ -3,6 +3,7 @@ package resolver import ( "database/sql" "encoding/json" + "fmt" "testing" "time" @@ -313,9 +314,11 @@ func TestResolver_CreateJob(t *testing.T) { } } }` + uuid := uuid.New() + spec := fmt.Sprintf(testspecs.DirectRequestSpecTemplate, uuid, uuid) variables := map[string]interface{}{ "input": map[string]interface{}{ - "TOML": testspecs.DirectRequestSpec, + "TOML": spec, }, } invalid := map[string]interface{}{ @@ -323,7 +326,7 @@ func TestResolver_CreateJob(t *testing.T) { "TOML": "some wrong value", }, } - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) + jb, err := directrequest.ValidatedDirectRequestSpec(spec) assert.NoError(t, err) d, err := json.Marshal(map[string]interface{}{ diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 45e92a147d3..48d432138a8 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -35,13 +35,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -206,3 +206,9 @@ DevWebServer = false OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false + +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index ff7eb832c9c..4b53396b94c 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -35,13 +35,19 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = true -ServerPubKey = 'test-pub-key' -URL = 'https://prom.test' BufferSize = 1234 MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true +URL = '' +ServerPubKey = '' + +[[TelemetryIngress.Endpoints]] +Network = 'EVM' +ChainID = '1' +URL = 'endpoint-1.test' +ServerPubKey = 'test-pub-key-1' [AuditLogger] Enabled = true @@ -142,7 +148,7 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true [P2P.V1] -Enabled = false +Enabled = true AnnounceIP = '1.2.3.4' AnnouncePort = 1234 BootstrapCheckInterval = '1m0s' @@ -155,7 +161,7 @@ NewStreamTimeout = '1s' PeerstoreWriteInterval = '1m0s' [P2P.V2] -Enabled = true +Enabled = false AnnounceAddresses = ['a', 'b', 'c'] DefaultBootstrappers = ['12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@foo:42/bar:10', '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw@test:99'] DeltaDial = '1m0s' @@ -207,6 +213,16 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = 'localhost:4317' +NodeID = 'NodeID' +SamplingRatio = 1.0 + +[Tracing.Attributes] +env = 'dev' +test = 'load' + [[EVM]] ChainID = '1' Enabled = false @@ -289,6 +305,7 @@ PollFailureThreshold = 5 PollInterval = '1m0s' SelectionMode = 'HighestHead' SyncThreshold = 13 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 11 diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 665de9be8cb..1dcbfe3a830 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -35,13 +35,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = true @@ -142,7 +142,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -155,7 +155,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -207,6 +207,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -271,6 +277,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 @@ -355,6 +362,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 @@ -433,6 +441,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/core/web/router_test.go b/core/web/router_test.go index 424ef4296f4..18177a1ac28 100644 --- a/core/web/router_test.go +++ b/core/web/router_test.go @@ -6,6 +6,8 @@ import ( "net/http/httptest" "testing" + "github.com/google/uuid" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -39,7 +41,7 @@ func TestTokenAuthRequired_SessionCredentials(t *testing.T) { ts := httptest.NewServer(router) defer ts.Close() - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) resp, cleanup := client.Post("/v2/bridge_types/", nil) defer cleanup() @@ -57,7 +59,7 @@ func TestTokenAuthRequired_TokenCredentials(t *testing.T) { eia := auth.NewToken() url := cltest.WebURL(t, "http://localhost:8888") eir := &bridges.ExternalInitiatorRequest{ - Name: "bitcoin", + Name: uuid.New().String(), URL: &url, } ea, err := bridges.NewExternalInitiator(eia, eir) @@ -89,7 +91,7 @@ func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { eia := auth.NewToken() url := cltest.WebURL(t, "http://localhost:8888") eir := &bridges.ExternalInitiatorRequest{ - Name: "bitcoin", + Name: uuid.New().String(), URL: &url, } ea, err := bridges.NewExternalInitiator(eia, eir) diff --git a/core/web/sessions_controller_test.go b/core/web/sessions_controller_test.go index 41865868b80..7184e3f95b4 100644 --- a/core/web/sessions_controller_test.go +++ b/core/web/sessions_controller_test.go @@ -26,6 +26,9 @@ func TestSessionsController_Create(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) + user := cltest.MustRandomUser(t) + require.NoError(t, app.SessionORM().CreateUser(&user)) + client := clhttptest.NewTestLocalOnlyHTTPClient() tests := []struct { name string @@ -33,9 +36,9 @@ func TestSessionsController_Create(t *testing.T) { password string wantSession bool }{ - {"incorrect pwd", cltest.APIEmailAdmin, "incorrect", false}, + {"incorrect pwd", user.Email, "incorrect", false}, {"incorrect email", "incorrect@test.net", cltest.Password, false}, - {"correct", cltest.APIEmailAdmin, cltest.Password, true}, + {"correct", user.Email, cltest.Password, true}, } for _, test := range tests { @@ -76,7 +79,7 @@ func TestSessionsController_Create(t *testing.T) { func mustInsertSession(t *testing.T, q pg.Q, session *sessions.Session) { sql := "INSERT INTO sessions (id, email, last_used, created_at) VALUES ($1, $2, $3, $4) RETURNING *" - _, err := q.Exec(sql, session.ID, cltest.APIEmailAdmin, session.LastUsed, session.CreatedAt) + _, err := q.Exec(sql, session.ID, session.Email, session.LastUsed, session.CreatedAt) require.NoError(t, err) } @@ -86,12 +89,16 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) + user := cltest.MustRandomUser(t) + require.NoError(t, app.SessionORM().CreateUser(&user)) + staleSession := cltest.NewSession() staleSession.LastUsed = time.Now().Add(-cltest.MustParseDuration(t, "241h")) + staleSession.Email = user.Email q := pg.NewQ(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) mustInsertSession(t, q, &staleSession) - body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, cltest.APIEmailAdmin, cltest.Password) + body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, user.Email, cltest.Password) resp, err := http.Post(app.Server.URL+"/sessions", "application/json", bytes.NewBufferString(body)) assert.NoError(t, err) defer func() { assert.NoError(t, resp.Body.Close()) }() @@ -116,7 +123,11 @@ func TestSessionsController_Destroy(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) + user := cltest.MustRandomUser(t) + require.NoError(t, app.SessionORM().CreateUser(&user)) + correctSession := sessions.NewSession() + correctSession.Email = user.Email q := pg.NewQ(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) mustInsertSession(t, q, &correctSession) @@ -158,11 +169,17 @@ func TestSessionsController_Destroy_ReapSessions(t *testing.T) { q := pg.NewQ(app.GetSqlxDB(), app.GetLogger(), app.GetConfig().Database()) require.NoError(t, app.Start(testutils.Context(t))) + user := cltest.MustRandomUser(t) + require.NoError(t, app.SessionORM().CreateUser(&user)) + correctSession := sessions.NewSession() + correctSession.Email = user.Email + mustInsertSession(t, q, &correctSession) cookie := cltest.MustGenerateSessionCookie(t, correctSession.ID) staleSession := cltest.NewSession() + staleSession.Email = user.Email staleSession.LastUsed = time.Now().Add(-cltest.MustParseDuration(t, "241h")) mustInsertSession(t, q, &staleSession) diff --git a/core/web/solana_chains_controller_test.go b/core/web/solana_chains_controller_test.go index 3112c42856f..5d6dc7424a2 100644 --- a/core/web/solana_chains_controller_test.go +++ b/core/web/solana_chains_controller_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/utils" "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" + "github.com/smartcontractkit/chainlink-solana/pkg/solana" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -80,7 +80,7 @@ Nodes = [] t.Run(tc.name, func(t *testing.T) { t.Parallel() - controller := setupSolanaChainsControllerTestV2(t, &solana.SolanaConfig{ + controller := setupSolanaChainsControllerTestV2(t, &solana.TOMLConfig{ ChainID: ptr(validId), Chain: config.Chain{ SkipPreflight: ptr(false), @@ -111,13 +111,13 @@ Nodes = [] func Test_SolanaChainsController_Index(t *testing.T) { t.Parallel() - chainA := &solana.SolanaConfig{ + chainA := &solana.TOMLConfig{ ChainID: ptr(fmt.Sprintf("ChainlinktestA-%d", rand.Int31n(999999))), Chain: config.Chain{ TxTimeout: utils.MustNewDuration(time.Hour), }, } - chainB := &solana.SolanaConfig{ + chainB := &solana.TOMLConfig{ ChainID: ptr(fmt.Sprintf("ChainlinktestB-%d", rand.Int31n(999999))), Chain: config.Chain{ SkipPreflight: ptr(false), @@ -175,7 +175,7 @@ type TestSolanaChainsController struct { client cltest.HTTPClientCleaner } -func setupSolanaChainsControllerTestV2(t *testing.T, cfgs ...*solana.SolanaConfig) *TestSolanaChainsController { +func setupSolanaChainsControllerTestV2(t *testing.T, cfgs ...*solana.TOMLConfig) *TestSolanaChainsController { for i := range cfgs { cfgs[i].SetDefaults() } @@ -186,7 +186,7 @@ func setupSolanaChainsControllerTestV2(t *testing.T, cfgs ...*solana.SolanaConfi app := cltest.NewApplicationWithConfig(t, cfg) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return &TestSolanaChainsController{ app: app, diff --git a/core/web/solana_keys_controller_test.go b/core/web/solana_keys_controller_test.go index b32a844a395..3dfbcfd252a 100644 --- a/core/web/solana_keys_controller_test.go +++ b/core/web/solana_keys_controller_test.go @@ -41,7 +41,7 @@ func TestSolanaKeysController_Create_HappyPath(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) keyStore := app.GetKeyStore() response, cleanup := client.Post("/v2/keys/solana", nil) @@ -99,7 +99,7 @@ func setupSolanaKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, key require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, app.KeyStore.Solana().Add(cltest.DefaultSolanaKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index df750586a46..f9a2c627932 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -61,16 +61,12 @@ func (tc *SolanaTransfersController) Create(c *gin.Context) { err = relayer.Transact(c, tr.From.String(), tr.To.String(), amount, !tr.AllowHigherAmounts) if err != nil { - switch err { - case chains.ErrNotFound, chains.ErrChainIDEmpty: + if errors.Is(err, chains.ErrNotFound) || errors.Is(err, chains.ErrChainIDEmpty) { jsonAPIError(c, http.StatusBadRequest, err) return - case nil: - break - default: - jsonAPIError(c, http.StatusInternalServerError, err) - return } + jsonAPIError(c, http.StatusInternalServerError, err) + return } resource := presenters.NewSolanaMsgResource("sol_transfer_"+uuid.New().String(), tr.SolanaChainID) diff --git a/core/web/starknet_keys_controller_test.go b/core/web/starknet_keys_controller_test.go index c3337e14d2d..a633b4f16c9 100644 --- a/core/web/starknet_keys_controller_test.go +++ b/core/web/starknet_keys_controller_test.go @@ -41,7 +41,7 @@ func TestStarkNetKeysController_Create_HappyPath(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) keyStore := app.GetKeyStore() response, cleanup := client.Post("/v2/keys/starknet", nil) @@ -99,7 +99,7 @@ func setupStarkNetKeysControllerTests(t *testing.T) (cltest.HTTPClientCleaner, k require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, app.KeyStore.StarkNet().Add(cltest.DefaultStarkNetKey)) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) return client, app.GetKeyStore() } diff --git a/core/web/user_controller_test.go b/core/web/user_controller_test.go index cdb9c9953da..a11082ff6a4 100644 --- a/core/web/user_controller_test.go +++ b/core/web/user_controller_test.go @@ -91,7 +91,7 @@ func TestUserController_CreateUser(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) longPassword := strings.Repeat("x", sessions.MaxBcryptPasswordLength+1) @@ -186,8 +186,7 @@ func TestUserController_UpdateRole(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - u := cltest.User{} - client := app.NewHTTPClient(&u) + client := app.NewHTTPClient(nil) user := cltest.MustRandomUser(t) err := app.SessionORM().CreateUser(&user) require.NoError(t, err) @@ -234,7 +233,7 @@ func TestUserController_DeleteUser(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) user := cltest.MustRandomUser(t) err := app.SessionORM().CreateUser(&user) require.NoError(t, err) @@ -260,7 +259,7 @@ func TestUserController_NewAPIToken(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) req, err := json.Marshal(sessions.ChangeAuthTokenRequest{ Password: cltest.Password, }) @@ -282,7 +281,7 @@ func TestUserController_NewAPIToken_unauthorized(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) req, err := json.Marshal(sessions.ChangeAuthTokenRequest{ Password: "wrong-password", }) @@ -298,7 +297,7 @@ func TestUserController_DeleteAPIKey(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) req, err := json.Marshal(sessions.ChangeAuthTokenRequest{ Password: cltest.Password, }) @@ -315,7 +314,7 @@ func TestUserController_DeleteAPIKey_unauthorized(t *testing.T) { app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) - client := app.NewHTTPClient(&cltest.User{}) + client := app.NewHTTPClient(nil) req, err := json.Marshal(sessions.ChangeAuthTokenRequest{ Password: "wrong-password", }) diff --git a/core/testdata/tomlspecs/webhook-job-spec-with-empty-json.toml b/core/web/webhook-spec-template.yml similarity index 86% rename from core/testdata/tomlspecs/webhook-job-spec-with-empty-json.toml rename to core/web/webhook-spec-template.yml index 1f99dcb3d17..b490a15dda1 100644 --- a/core/testdata/tomlspecs/webhook-job-spec-with-empty-json.toml +++ b/core/web/webhook-spec-template.yml @@ -1,6 +1,7 @@ type = "webhook" schemaVersion = 1 -externalJobID = "0EEC7E1D-D0D2-476C-A1A8-72DFB6633F53" +externalJobID = "%s" +name = "%s" observationSource = """ fetch [type=bridge name="fetch_bridge"] parse_request [type=jsonparse path="data,result"]; diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7f0b80ebcfe..f122b365d28 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,50 +9,82 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +... + + + +## 2.7.0 - 2023-11-14 + ### Added -- Simple password use in production builds is now disallowed - nodes with this configuration will not boot and will not pass config validation. +- Added new configuration field named `LeaseDuration` for `EVM.NodePool` that will periodically check if internal subscriptions are connected to the "best" (as defined by the `SelectionMode`) node and switch to it if necessary. Setting this value to `0s` will disable this feature. +- Added multichain telemetry support. Each network/chainID pair must be configured using the new fields: +```toml +[[TelemetryIngress.Endpoints]] +Network = '...' # e.g. EVM. Solana, Starknet, Cosmos +ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta +URL = '...' +ServerPubKey = '...' +``` +These will eventually replace `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey`. Setting `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` alongside `[[TelemetryIngress.Endpoints]]` will prevent the node from booting. Only one way of configuring telemetry endpoints is supported. +- Added bridge_name label to `pipeline_tasks_total_finished` prometheus metric. This should make it easier to see directly what bridge was failing out from the CL NODE perspective. + +- LogPoller will now use finality tags to dynamically determine finality on evm chains if `UseFinalityTags=true`, rather than the fixed `FinalityDepth` specified in toml config + +### Changed + +- `P2P.V1` is now disabled (`Enabled = false`) by default. It must be explicitly enabled with `true` to be used. However, it is deprecated and will be removed in the future. +- `P2P.V2` is now enabled (`Enabled = true`) by default. + +### Upcoming Required Configuration Changes +Starting in `v2.9.0`: +- `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` will no longer be allowed. Any TOML configuration that sets this fields will prevent the node from booting. These fields will be replaced by `[[TelemetryIngress.Endpoints]]` +- `P2P.V1` will no longer be supported and must not be set in TOML configuration in order to boot. Use `P2P.V2` instead. If you are using both, `V1` can simply be removed. + +### Removed + +- Removed the ability to set a next nonce value for an address through CLI + +## 2.6.0 - 2023-10-18 + +### Added + +- Simple password use in production builds is now disallowed - nodes with this configuration will not boot and will not pass config validation. - Helper migrations function for injecting env vars into goose migrations. This was done to inject chainID into evm chain id not null in specs migrations. - OCR2 jobs now support querying the state contract for configurations if it has been deployed. This can help on chains such as BSC which "manage" state bloat by arbitrarily deleting logs older than a certain date. In this case, if logs are missing we will query the contract directly and retrieve the latest config from chain state. Chainlink will perform no extra RPC calls unless the job spec has this feature explicitly enabled. On chains that require this, nops may see an increase in RPC calls. This can be enabled for OCR2 jobs by specifying `ConfigContractAddress` in the relay config TOML. ### Removed -- Removed support for sending telemetry to the deprecated Explorer service. All nodes will have to remove `Explorer` related keys from TOML configuration and env vars. +- Removed support for sending telemetry to the deprecated Explorer service. All nodes will have to remove `Explorer` related keys from TOML configuration and env vars. - Removed default evmChainID logic where evmChainID was implicitly injected into the jobspecs based on node EVM chainID toml configuration. All newly created jobs(that have evmChainID field) will have to explicitly define evmChainID in the jobspec. - Removed keyset migration that migrated v1 keys to v2 keys. All keys should've been migrated by now, and we don't permit creation of new v1 keys anymore - All nodes will have to remove the following secret configurations: - * `Explorer.AccessKey` - * `Explorer.Secret` - - All nodes will have to remove the following configuration field: `ExplorerURL` +All nodes will have to remove the following secret configurations: + +- `Explorer.AccessKey` +- `Explorer.Secret` + +All nodes will have to remove the following configuration field: `ExplorerURL` ### Fixed + - Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: -```[ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 ``` + `[ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 ` - Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. - `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, recipient and `unstarted` state were returned. - Fixed a bug where `evmChainId` is requested instead of `id` or `evm-chain-id` in CLI error verbatim - Fixed a bug that would cause the node to shut down while performing backup - Fixed health checker to include more services in the prometheus `health` metric and HTTP `/health` endpoint - - +- Fixed a bug where prices would not be parsed correctly in telemetry data ## 2.5.0 - 2023-09-13 -- Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: - ``` - [ERROR] Error in transaction, rolling back: session missing or expired, please login again pg/transaction.go:118 - ``` -- Fixed a bug that was preventing job runs to be displayed when the job `chainID` was disabled. -- `chainlink txs evm create` returns a transaction hash for the attempted transaction in the CLI. Previously only the sender, receipient and `unstarted` state were returned. - ### Added - New prometheus metrics for mercury: - - `mercury_price_feed_missing` - - `mercury_price_feed_errors` - Nops may wish to add alerting on these. + - `mercury_price_feed_missing` + - `mercury_price_feed_errors` + Nops may wish to add alerting on these. ### Upcoming Required Configuration Change diff --git a/docs/CONFIG.md b/docs/CONFIG.md index ceb3d3dfe08..d97cbabd233 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -270,13 +270,13 @@ Logging toggles verbose logging of the raw telemetry messages being sent. ```toml ServerPubKey = 'test-pub-key' # Example ``` -ServerPubKey is the public key of the telemetry server. +ServerPubKey is the public key of the telemetry server. This field will be removed in a furture version ### URL ```toml URL = 'https://prom.test' # Example ``` -URL is where to send telemetry. +URL is where to send telemetry. This field will be removed in a furture version ### BufferSize ```toml @@ -308,6 +308,40 @@ UseBatchSend = true # Default ``` UseBatchSend toggles sending telemetry to the ingress server using the batch client. +## TelemetryIngress.Endpoints +```toml +[[TelemetryIngress.Endpoints]] # Example +Network = 'EVM' # Example +ChainID = '111551111' # Example +ServerPubKey = 'test-pub-key-111551111-evm' # Example +URL = 'localhost-111551111-evm:9000' # Example +``` + + +### Network +```toml +Network = 'EVM' # Example +``` +Network aka EVM, Solana, Starknet + +### ChainID +```toml +ChainID = '111551111' # Example +``` +ChainID of the network + +### ServerPubKey +```toml +ServerPubKey = 'test-pub-key-111551111-evm' # Example +``` +ServerPubKey is the public key of the telemetry server. + +### URL +```toml +URL = 'localhost-111551111-evm:9000' # Example +``` +URL is where to send telemetry. + ## AuditLogger ```toml [AuditLogger] @@ -947,6 +981,8 @@ If both are configured, then for each link with another peer, V2 networking will automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. +Note: P2P.V1 is deprecated will be removed in the future. + All nodes in the OCR network should share the same networking stack. ### IncomingMessageBufferSize @@ -983,7 +1019,7 @@ TraceLogging enables trace level logging. ## P2P.V1 ```toml [P2P.V1] -Enabled = true # Default +Enabled = false # Default AnnounceIP = '1.2.3.4' # Example AnnouncePort = 1337 # Example BootstrapCheckInterval = '20s' # Default @@ -995,11 +1031,11 @@ ListenPort = 1337 # Example NewStreamTimeout = '10s' # Default PeerstoreWriteInterval = '5m' # Default ``` - +P2P.V1 is deprecated and will be removed in a future version. ### Enabled ```toml -Enabled = true # Default +Enabled = false # Default ``` Enabled enables P2P V1. @@ -1085,7 +1121,7 @@ PeerstoreWriteInterval controls how often the peerstore for the OCR V1 networkin ## P2P.V2 ```toml [P2P.V2] -Enabled = false # Default +Enabled = true # Default AnnounceAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example DefaultBootstrappers = ['12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U@1.2.3.4:9999', '12D3KooWM55u5Swtpw9r8aFLQHEtw7HR4t44GdNs654ej5gRs2Dh@example.com:1234'] # Example DeltaDial = '15s' # Default @@ -1096,7 +1132,7 @@ ListenAddresses = ['1.2.3.4:9999', '[a52d:0:a88:1274::abcd]:1337'] # Example ### Enabled ```toml -Enabled = false # Default +Enabled = true # Default ``` Enabled enables P2P V2. Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. @@ -1422,6 +1458,53 @@ DisableRateLimiting = false # Default ``` DisableRateLimiting skips ratelimiting on asset requests. +## Tracing +```toml +[Tracing] +Enabled = false # Default +CollectorTarget = "localhost:4317" # Example +NodeID = "NodeID" # Example +SamplingRatio = 1.0 # Example +``` + + +### Enabled +```toml +Enabled = false # Default +``` +Enabled turns trace collection on or off. On requires an OTEL Tracing Collector. + +### CollectorTarget +```toml +CollectorTarget = "localhost:4317" # Example +``` +CollectorTarget is the logical address of the OTEL Tracing Collector. + +### NodeID +```toml +NodeID = "NodeID" # Example +``` +NodeID is an unique name for this node relative to any other node traces are collected for. + +### SamplingRatio +```toml +SamplingRatio = 1.0 # Example +``` +SamplingRatio is the ratio of traces to sample for this node. + +## Tracing.Attributes +```toml +[Tracing.Attributes] +env = "test" # Example +``` +Tracing.Attributes are user specified key-value pairs to associate in the context of the traces + +### env +```toml +env = "test" # Example +``` +env is an example user specified key-value pair + ## EVM EVM defaults depend on ChainID: @@ -1490,6 +1573,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -1568,6 +1652,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -1646,6 +1731,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -1724,6 +1810,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -1803,6 +1890,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -1881,6 +1969,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -1959,6 +2048,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2038,6 +2128,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2116,6 +2207,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2193,6 +2285,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2270,6 +2363,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2348,6 +2442,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2427,6 +2522,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2505,6 +2601,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2583,6 +2680,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2661,6 +2759,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -2740,6 +2839,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -2818,6 +2918,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -2895,6 +2996,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -2973,6 +3075,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3050,6 +3153,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3128,6 +3232,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -3205,6 +3310,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3283,6 +3389,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3362,6 +3469,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3440,6 +3548,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3518,6 +3627,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3596,6 +3706,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3674,6 +3785,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3688,6 +3800,162 @@ GasLimit = 5300000

+
Linea Goerli (59140)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +FinalityDepth = 15 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '15s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 3 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '0s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '3m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '1 gwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 40 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+ +
Linea Mainnet (59144)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +FinalityDepth = 300 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '15s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 3 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '0s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '3m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'BlockHistory' +PriceDefault = '20 gwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '400 mwei' +LimitDefault = 500000 +LimitMax = 500000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 40 +BumpThreshold = 3 +EIP1559DynamicFees = false +FeeCapDefault = '100 gwei' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 8 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 350 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 5 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 4 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 5300000 +``` + +

+
Polygon Mumbai (80001)

```toml @@ -3752,6 +4020,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -3830,6 +4099,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3909,6 +4179,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -3988,6 +4259,86 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 10 +LeaseDuration = '0s' + +[OCR] +ContractConfirmations = 1 +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +ObservationGracePeriod = '1s' + +[OCR2] +[OCR2.Automation] +GasLimit = 14500000 +``` + +

+ +
Arbitrum Sepolia (421614)

+ +```toml +AutoCreateKey = true +BlockBackfillDepth = 10 +BlockBackfillSkip = false +ChainType = 'arbitrum' +FinalityDepth = 50 +FinalityTagEnabled = false +LogBackfillBatchSize = 1000 +LogPollInterval = '1s' +LogKeepBlocksDepth = 100000 +MinIncomingConfirmations = 3 +MinContractPayment = '0.00001 link' +NonceAutoSync = true +NoNewHeadsThreshold = '0s' +RPCDefaultBatchSize = 250 +RPCBlockQueryDelay = 1 + +[Transactions] +ForwardersEnabled = false +MaxInFlight = 16 +MaxQueued = 250 +ReaperInterval = '1h0m0s' +ReaperThreshold = '168h0m0s' +ResendAfterThreshold = '1m0s' + +[BalanceMonitor] +Enabled = true + +[GasEstimator] +Mode = 'Arbitrum' +PriceDefault = '100 mwei' +PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether' +PriceMin = '0' +LimitDefault = 500000 +LimitMax = 1000000000 +LimitMultiplier = '1' +LimitTransfer = 21000 +BumpMin = '5 gwei' +BumpPercent = 20 +BumpThreshold = 0 +EIP1559DynamicFees = false +FeeCapDefault = '1 micro' +TipCapDefault = '1 wei' +TipCapMin = '1 wei' + +[GasEstimator.BlockHistory] +BatchSize = 25 +BlockHistorySize = 0 +CheckInclusionBlocks = 12 +CheckInclusionPercentile = 90 +TransactionPercentile = 60 + +[HeadTracker] +HistoryDepth = 100 +MaxBufferSize = 3 +SamplingInterval = '1s' + +[NodePool] +PollFailureThreshold = 5 +PollInterval = '10s' +SelectionMode = 'HighestHead' +SyncThreshold = 10 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -4065,6 +4416,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -4142,6 +4494,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 1 @@ -4220,6 +4573,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -4298,6 +4652,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -4376,6 +4731,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [OCR] ContractConfirmations = 4 @@ -4996,6 +5352,7 @@ PollFailureThreshold = 5 # Default PollInterval = '10s' # Default SelectionMode = 'HighestHead' # Default SyncThreshold = 5 # Default +LeaseDuration = '0s' # Default ``` The node pool manages multiple RPC endpoints. @@ -5024,6 +5381,7 @@ SelectionMode = 'HighestHead' # Default SelectionMode controls node selection strategy: - HighestHead: use the node with the highest head number - RoundRobin: rotate through nodes, per-request +- PriorityLevel: use the node with the smallest order number - TotalDifficulty: use the node with the greatest total difficulty ### SyncThreshold @@ -5035,6 +5393,17 @@ Depending on `SelectionMode`, this represents a difference in the number of bloc Set to 0 to disable this check. +### LeaseDuration +```toml +LeaseDuration = '0s' # Default +``` +LeaseDuration is the minimum duration that the selected "best" node (as defined by SelectionMode) will be used, +before switching to a better one if available. It also controls how often the lease check is done. +Setting this to a low value (under 1m) might cause RPC to switch too aggressively. +Recommended value is over 5m + +Set to '0s' to disable + ## EVM.OCR ```toml [EVM.OCR] diff --git a/docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md b/docs/core/TX_MANAGER_ARCHITECTURE.md similarity index 86% rename from docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md rename to docs/core/TX_MANAGER_ARCHITECTURE.md index 37480a88c4c..6e0ff946ffc 100644 --- a/docs/core/BULLETPROOF_TX_MANAGER_ARCHITECTURE.md +++ b/docs/core/TX_MANAGER_ARCHITECTURE.md @@ -4,28 +4,28 @@ ## Finite state machine -### `eth_txes.state` +### `evm.txes.state` `unstarted` | | v `in_progress` (only one per key) -| \ -| \ -v v -`fatal_error` `unconfirmed` - | ^ - | | - v | - `confirmed` +| \ +| \ +v v +`fatal_error` `unconfirmed` +| ^ +| | +v | +`confirmed` ### `eth_tx_attempts.state` `in_progress` -| ^ -| | -v | +| ^ +| | +v | `broadcast` # Data structures @@ -42,7 +42,7 @@ EB - EthBroadcaster EC - EthConfirmer -`eth_txes` has five possible states: +`evm.txes` has five possible states: - EB ⚫️ `unstarted` - EB 🟠 `in_progress` @@ -57,12 +57,6 @@ EC - EthConfirmer An attempt may have 0 or more `eth_receipts` indicating that the transaction has been mined into a block. This block may or may not exist as part of the canonical longest chain. -`keys` has a field: - -- `next_nonce` - -Which tracks the nonce that is available to use for the next transaction. It is only updated after a successful broadcast has occurred. - # Components BulletproofTxManager is split into three components, each of which has a clearly delineated set of responsibilities. @@ -71,7 +65,7 @@ BulletproofTxManager is split into three components, each of which has a clearly Conceptually, **EthTx** defines the transaction. -**EthTx** is responsible for generating the transaction criteria and inserting the initial `unstarted` row into the `eth_txes` table. +**EthTx** is responsible for generating the transaction criteria and inserting the initial `unstarted` row into the `evm.txes` table. **EthTx** guarantees that the transaction is defined with the following criteria: @@ -87,9 +81,9 @@ EthTx should wait until it's transaction confirms before marking the task as com ## EthBroadcaster -Conceptually, **EthBroadcaster** assigns a nonce to a transaction and ensures that it is valid. It alone controls the `keys.next_nonce` field. +Conceptually, **EthBroadcaster** assigns a nonce to a transaction and ensures that it is valid. It alone maintains the next usable sequence for a transaction. -**EthBroadcaster** monitors `eth_txes` for transactions that need to be broadcast, assigns nonces and ensures that at least one eth node somewhere has placed the transaction into its mempool. +**EthBroadcaster** monitors `evm.txes` for transactions that need to be broadcast, assigns nonces and ensures that at least one eth node somewhere has placed the transaction into its mempool. It does not guarantee eventual confirmation! @@ -97,8 +91,8 @@ A whole host of other things can subsequently go wrong such as transactions bein **EthBroadcaster** makes the following guarantees: -- A gapless, monotonically increasing sequence of nonces for `eth_txes` (scoped to key). -- Transition of `eth_txes` from `unstarted` to either `fatal_error` or `unconfirmed`. +- A gapless, monotonically increasing sequence of nonces for `evm.txes` (scoped to key). +- Transition of `evm.txes` from `unstarted` to either `fatal_error` or `unconfirmed`. - If final state is `fatal_error` then the nonce is unassigned, and it is impossible that this transaction could ever be mined into a block. - If final state is `unconfirmed` then a saved `eth_transaction_attempt` exists. - If final state is `unconfirmed` then an eth node somewhere has accepted this transaction into its mempool at least once. @@ -132,7 +126,7 @@ Find all transactions confirmed within the past `ETH_FINALITY_DEPTH` blocks and **EthConfirmer** makes the following guarantees: - All transactions will eventually be confirmed on the canonical longest chain, unless a reorg occurs that is deeper than `ETH_FINALITY_DEPTH` blocks. -- In the case that an external wallet used the nonce, we will ensure that *a* transaction exists at this nonce up to a depth of `ETH_FINALITY_DEPTH` blocks but it most likely will not be the transaction in our database. +- In the case that an external wallet used the nonce, we will ensure that _a_ transaction exists at this nonce up to a depth of `ETH_FINALITY_DEPTH` blocks but it most likely will not be the transaction in our database. Note that since checking for inclusion in the longest chain can now be done cheaply, without any calls to the eth node, `ETH_FINALITY_DEPTH` can be set to something quite large without penalty (e.g. 50 or 100). diff --git a/go.mod b/go.mod index d0fd99a8287..df970160acc 100644 --- a/go.mod +++ b/go.mod @@ -30,10 +30,11 @@ require ( github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.1 github.com/gorilla/websocket v1.5.0 - github.com/grafana/pyroscope-go v1.0.2 + github.com/grafana/pyroscope-go v1.0.4 github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 - github.com/hashicorp/go-plugin v1.4.10 + github.com/hashicorp/consul/sdk v0.14.1 + github.com/hashicorp/go-plugin v1.5.2 github.com/hdevalence/ed25519consensus v0.1.0 github.com/jackc/pgconn v1.14.1 github.com/jackc/pgtype v1.14.0 @@ -55,22 +56,22 @@ require ( github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 - github.com/pressly/goose/v3 v3.15.0 - github.com/prometheus/client_golang v1.16.0 - github.com/prometheus/client_model v0.4.0 + github.com/pressly/goose/v3 v3.15.1 + github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.44.0 github.com/prometheus/prometheus v0.46.0 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 - github.com/shirou/gopsutil/v3 v3.23.8 + github.com/shirou/gopsutil/v3 v3.23.9 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 - github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb + github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb @@ -89,15 +90,14 @@ require ( go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/multierr v1.11.0 - go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.11.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 - golang.org/x/net v0.12.0 - golang.org/x/sync v0.3.0 - golang.org/x/term v0.10.0 - golang.org/x/text v0.11.0 + golang.org/x/sync v0.4.0 + golang.org/x/term v0.13.0 + golang.org/x/text v0.13.0 golang.org/x/time v0.3.0 - golang.org/x/tools v0.11.0 + golang.org/x/tools v0.14.0 gonum.org/v1/gonum v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 @@ -123,7 +123,6 @@ require ( github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect - github.com/benbjohnson/clock v1.3.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -131,6 +130,7 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect @@ -196,11 +196,12 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/gorilla/context v1.1.1 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.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 @@ -235,7 +236,7 @@ require ( github.com/jmhodges/levigo v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -309,7 +310,7 @@ require ( github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // 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/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -348,19 +349,22 @@ require ( go.dedis.ch/protobuf v1.0.11 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/atomic v1.11.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/sdk v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.56.2 // indirect + google.golang.org/grpc v1.58.3 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -378,7 +382,7 @@ replace ( github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 - github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 + github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f diff --git a/go.sum b/go.sum index 59356146049..59286787c2e 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/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= @@ -243,8 +241,8 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= 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/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= 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= @@ -622,10 +620,10 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad 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/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= 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= @@ -633,14 +631,16 @@ github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLt 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.0-rc.0 h1:mdLirNAJBxnGgyB6pjZLcs6ue/6eZGBui6gXspfq4ks= -github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0/go.mod h1:kdXbOySqcQeTxiqglW7aahTmWZy3Pgi6SYL36yvKeyA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tggROQKKcnh4eItay6z/HbHLqghBxS8g7pyMhmDio= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0/go.mod h1:hKAkSgNkL0FII46ZkJcpVEAai4KV+swlIWCKfekd1pA= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= 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.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= 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= @@ -652,6 +652,8 @@ github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfm 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/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= 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= @@ -681,8 +683,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX 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/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +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.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -884,8 +886,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 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.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= @@ -1325,10 +1327,10 @@ 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/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.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= +github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 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= @@ -1363,20 +1365,20 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 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.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= 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.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +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-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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +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.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= @@ -1387,8 +1389,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R 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.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.46.0 h1:9JSdXnsuT6YsbODEhSQMwxNkGwPExfmzqG73vCMk/Kw= github.com/prometheus/prometheus v0.46.0/go.mod h1:10L5IJE5CEsjee1FnOcVswYXlPIscDWWt3IJ2UDYrz4= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1439,8 +1441,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg 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/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -1457,18 +1459,18 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 h1:Db333w+fSm2e18LMikcIQHIZqgxZruW9uCUGJLUC9mI= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= @@ -1660,16 +1662,22 @@ 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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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= @@ -1697,8 +1705,9 @@ 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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -1739,8 +1748,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 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= @@ -1779,8 +1788,8 @@ 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1841,8 +1850,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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= @@ -1867,8 +1876,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ 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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -1961,16 +1970,18 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.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 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= 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 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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= @@ -1982,8 +1993,8 @@ 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.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -2057,8 +2068,8 @@ 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.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= @@ -2177,8 +2188,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= -google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= 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= @@ -2255,20 +2266,20 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= -modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ= -modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo= +modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= +modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= -modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw= +modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= diff --git a/integration-tests/Makefile b/integration-tests/Makefile index 287bb939635..f26518c0076 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -70,6 +70,17 @@ build_test_image: build_push_docker_image: docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop +#Build a chainlink docker image in plugin mode for local testing and push to k3d registry +.PHONY: build_push_plugin_docker_image +build_push_plugin_docker_image: + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop + +# Spins up containers needed to collect traces for local testing +.PHONY: run_tracing +run_tracing: + cd ../.github/tracing + docker compose -f ../.github/tracing/local-smoke-docker-compose.yaml up + ## Test Runner .PHONY: run run: # Need to set network first in case it's unset. Doesn't matter for the runner @@ -188,4 +199,4 @@ run_test_with_local_image: build_docker_image SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ ARGS="$(args)" \ PRODUCT=$(product) \ - ./scripts/run_product_tests \ No newline at end of file + ./scripts/run_product_tests diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index e37c3738ff8..dcdca91cc78 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -72,7 +72,10 @@ func FundChainlinkNodesAddress( if err != nil { return err } - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress[keyIndex]) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } @@ -96,7 +99,10 @@ func FundChainlinkNodesAddresses( return err } for _, addr := range toAddress { - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(addr) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } @@ -369,7 +375,7 @@ func ReturnFunds(chainlinkNodes []*client.ChainlinkK8sClient, blockchainClient b } err = blockchainClient.ReturnFunds(decryptedKey.PrivateKey) if err != nil { - return err + log.Error().Err(err).Str("Address", fundedKeys[0].Address).Msg("Error returning funds from Chainlink node") } } } @@ -379,7 +385,10 @@ func ReturnFunds(chainlinkNodes []*client.ChainlinkK8sClient, blockchainClient b // FundAddresses will fund a list of addresses with an amount of native currency func FundAddresses(blockchain blockchain.EVMClient, amount *big.Float, addresses ...string) error { for _, address := range addresses { - gasEstimates, err := blockchain.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(address) + gasEstimates, err := blockchain.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go index d2e2fde3217..b65bac43bb1 100644 --- a/integration-tests/actions/actions_local.go +++ b/integration-tests/actions/actions_local.go @@ -3,7 +3,6 @@ package actions import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index fb94d6109b4..998b1ee89cf 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -11,19 +11,20 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" + + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -37,7 +38,7 @@ func BuildAutoOCR2ConfigVars( registrar string, deltaStage time.Duration, ) (contracts.OCRv2Config, error) { - return BuildAutoOCR2ConfigVarsWithKeyIndex(t, chainlinkNodes, registryConfig, registrar, deltaStage, 0) + return BuildAutoOCR2ConfigVarsWithKeyIndex(t, chainlinkNodes, registryConfig, registrar, deltaStage, 0, common.Address{}) } func BuildAutoOCR2ConfigVarsWithKeyIndex( @@ -47,6 +48,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndex( registrar string, deltaStage time.Duration, keyIndex int, + registryOwnerAddress common.Address, ) (contracts.OCRv2Config, error) { l := logging.GetTestLogger(t) S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndex(chainlinkNodes, keyIndex) @@ -147,7 +149,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndex( transmitters = append(transmitters, common.HexToAddress(string(transmitter))) } - onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar) + onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar, registryOwnerAddress) if err != nil { return contracts.OCRv2Config{}, err } @@ -201,7 +203,8 @@ func CreateOCRKeeperJobs( } _, err = bootstrapNode.MustCreateJob(bootstrapSpec) require.NoError(t, err, "Shouldn't fail creating bootstrap job on bootstrap node") - P2Pv2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PId, bootstrapNode.Name(), 6690) + // TODO: Use service name returned by chainlink-env once that is available + P2Pv2Bootstrapper := fmt.Sprintf("%s@%s-node-1:%d", bootstrapP2PId, bootstrapNode.Name(), 6690) for nodeIndex := 1; nodeIndex < len(chainlinkNodes); nodeIndex++ { nodeTransmitterAddress, err := chainlinkNodes[nodeIndex].EthAddresses() @@ -258,14 +261,14 @@ func DeployAutoOCRRegistryAndRegistrar( return registry, registrar } -func DeployConsumers(t *testing.T, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool) ([]contracts.KeeperConsumer, []*big.Int) { - upkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfUpkeeps, isLogTrigger) +func DeployConsumers(t *testing.T, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool, isMercury bool) ([]contracts.KeeperConsumer, []*big.Int) { + upkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfUpkeeps, isLogTrigger, isMercury) var upkeepsAddresses []string for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } upkeepIds := RegisterUpkeepContracts( - t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, isLogTrigger, + t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, isLogTrigger, isMercury, ) return upkeeps, upkeepIds } @@ -292,7 +295,7 @@ func DeployPerformanceConsumers( for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false) + upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false) return upkeeps, upkeepIds } @@ -313,7 +316,7 @@ func DeployPerformDataCheckerConsumers( for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false) + upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false) return upkeeps, upkeepIds } diff --git a/integration-tests/actions/automation_ocr_helpers_local.go b/integration-tests/actions/automation_ocr_helpers_local.go index 86738b0247d..ccc2eea99d8 100644 --- a/integration-tests/actions/automation_ocr_helpers_local.go +++ b/integration-tests/actions/automation_ocr_helpers_local.go @@ -10,20 +10,20 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" "github.com/rs/zerolog" - "gopkg.in/guregu/null.v4" - - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocr2keepers20config "github.com/smartcontractkit/ocr2keepers/pkg/v2/config" ocr2keepers30config "github.com/smartcontractkit/ocr2keepers/pkg/v3/config" + "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) func BuildAutoOCR2ConfigVarsLocal( @@ -32,8 +32,9 @@ func BuildAutoOCR2ConfigVarsLocal( registryConfig contracts.KeeperRegistrySettings, registrar string, deltaStage time.Duration, + registryOwnerAddress common.Address, ) (contracts.OCRv2Config, error) { - return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(l, chainlinkNodes, registryConfig, registrar, deltaStage, 0) + return BuildAutoOCR2ConfigVarsWithKeyIndexLocal(l, chainlinkNodes, registryConfig, registrar, deltaStage, 0, registryOwnerAddress) } func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( @@ -43,6 +44,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( registrar string, deltaStage time.Duration, keyIndex int, + registryOwnerAddress common.Address, ) (contracts.OCRv2Config, error) { S, oracleIdentities, err := GetOracleIdentitiesWithKeyIndexLocal(chainlinkNodes, keyIndex) if err != nil { @@ -146,7 +148,7 @@ func BuildAutoOCR2ConfigVarsWithKeyIndexLocal( transmitters = append(transmitters, common.HexToAddress(string(transmitter))) } - onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar) + onchainConfig, err := registryConfig.EncodeOnChainConfig(registrar, registryOwnerAddress) if err != nil { return contracts.OCRv2Config{}, err } diff --git a/integration-tests/actions/keeper_helpers.go b/integration-tests/actions/keeper_helpers.go index f824e75019d..edd0dc5f735 100644 --- a/integration-tests/actions/keeper_helpers.go +++ b/integration-tests/actions/keeper_helpers.go @@ -146,12 +146,12 @@ func DeployKeeperContracts( } registrar := DeployKeeperRegistrar(t, registryVersion, linkToken, registrarSettings, contractDeployer, client, registry) - upkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfUpkeeps, false) + upkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfUpkeeps, false, false) var upkeepsAddresses []string for _, upkeep := range upkeeps { upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false) + upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfUpkeeps, upkeepsAddresses, false, false) err = client.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -214,7 +214,7 @@ func DeployPerformanceKeeperContracts( upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false) + upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false) return registry, registrar, upkeeps, upkeepIds } @@ -270,7 +270,7 @@ func DeployPerformDataCheckerContracts( upkeepsAddresses = append(upkeepsAddresses, upkeep.Address()) } - upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false) + upkeepIds := RegisterUpkeepContracts(t, linkToken, linkFundsForEachUpkeep, client, upkeepGasLimit, registry, registrar, numberOfContracts, upkeepsAddresses, false, false) return registry, registrar, upkeeps, upkeepIds } @@ -328,17 +328,17 @@ func DeployUpkeepTranscoder( return transcoder } -func RegisterUpkeepContracts(t *testing.T, linkToken contracts.LinkToken, linkFunds *big.Int, client blockchain.EVMClient, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, isLogTrigger bool) []*big.Int { +func RegisterUpkeepContracts(t *testing.T, linkToken contracts.LinkToken, linkFunds *big.Int, client blockchain.EVMClient, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, isLogTrigger bool, isMercury bool) []*big.Int { checkData := make([][]byte, 0) for i := 0; i < numberOfContracts; i++ { checkData = append(checkData, []byte("0")) } return RegisterUpkeepContractsWithCheckData( t, linkToken, linkFunds, client, upkeepGasLimit, registry, registrar, - numberOfContracts, upkeepAddresses, checkData, isLogTrigger) + numberOfContracts, upkeepAddresses, checkData, isLogTrigger, isMercury) } -func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.LinkToken, linkFunds *big.Int, client blockchain.EVMClient, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, checkData [][]byte, isLogTrigger bool) []*big.Int { +func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.LinkToken, linkFunds *big.Int, client blockchain.EVMClient, upkeepGasLimit uint32, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, numberOfContracts int, upkeepAddresses []string, checkData [][]byte, isLogTrigger bool, isMercury bool) []*big.Int { l := logging.GetTestLogger(t) registrationTxHashes := make([]common.Hash, 0) upkeepIds := make([]*big.Int, 0) @@ -354,6 +354,7 @@ func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.Link 0, client.GetDefaultWallet().Address(), isLogTrigger, + isMercury, ) require.NoError(t, err, "Encoding the register request shouldn't fail") tx, err := linkToken.TransferAndCall(registrar.Address(), linkFunds, req) @@ -397,7 +398,7 @@ func RegisterUpkeepContractsWithCheckData(t *testing.T, linkToken contracts.Link return upkeepIds } -func DeployKeeperConsumers(t *testing.T, contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, numberOfContracts int, isLogTrigger bool) []contracts.KeeperConsumer { +func DeployKeeperConsumers(t *testing.T, contractDeployer contracts.ContractDeployer, client blockchain.EVMClient, numberOfContracts int, isLogTrigger bool, isMercury bool) []contracts.KeeperConsumer { l := logging.GetTestLogger(t) keeperConsumerContracts := make([]contracts.KeeperConsumer, 0) @@ -406,9 +407,17 @@ func DeployKeeperConsumers(t *testing.T, contractDeployer contracts.ContractDepl var keeperConsumerInstance contracts.KeeperConsumer var err error - if isLogTrigger { + if isMercury && isLogTrigger { + // v2.1 only: Log triggered based contract with Mercury enabled + keeperConsumerInstance, err = contractDeployer.DeployAutomationLogTriggeredStreamsLookupUpkeepConsumer() + } else if isMercury { + // v2.1 only: Conditional based contract with Mercury enabled + keeperConsumerInstance, err = contractDeployer.DeployAutomationStreamsLookupUpkeepConsumer(big.NewInt(1000), big.NewInt(5), false, true, false) // 1000 block test range + } else if isLogTrigger { + // v2.1 only: Log triggered based contract without Mercury keeperConsumerInstance, err = contractDeployer.DeployAutomationLogTriggerConsumer(big.NewInt(1000)) // 1000 block test range } else { + // v2.0 and v2.1: Conditional based contract without Mercury keeperConsumerInstance, err = contractDeployer.DeployKeeperConsumer(big.NewInt(5)) } @@ -581,14 +590,14 @@ func RegisterNewUpkeeps( upkeepGasLimit uint32, numberOfNewUpkeeps int, ) ([]contracts.KeeperConsumer, []*big.Int) { - newlyDeployedUpkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfNewUpkeeps, false) + newlyDeployedUpkeeps := DeployKeeperConsumers(t, contractDeployer, client, numberOfNewUpkeeps, false, false) var addressesOfNewUpkeeps []string for _, upkeep := range newlyDeployedUpkeeps { addressesOfNewUpkeeps = append(addressesOfNewUpkeeps, upkeep.Address()) } - newUpkeepIDs := RegisterUpkeepContracts(t, linkToken, big.NewInt(9e18), client, upkeepGasLimit, registry, registrar, numberOfNewUpkeeps, addressesOfNewUpkeeps, false) + newUpkeepIDs := RegisterUpkeepContracts(t, linkToken, big.NewInt(9e18), client, upkeepGasLimit, registry, registrar, numberOfNewUpkeeps, addressesOfNewUpkeeps, false, false) return newlyDeployedUpkeeps, newUpkeepIDs } diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index 0b20e4cfee7..b3fe6eb041f 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -4,6 +4,7 @@ import ( "crypto/ed25519" "encoding/hex" "fmt" + "net/http" "strings" "time" @@ -11,7 +12,7 @@ import ( "github.com/google/uuid" "github.com/lib/pq" "github.com/rs/zerolog/log" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -29,9 +30,9 @@ func CreateOCRv2JobsLocal( ocrInstances []contracts.OffchainAggregatorV2, bootstrapNode *client.ChainlinkClient, workerChainlinkNodes []*client.ChainlinkClient, - mockserver *ctfClient.MockserverClient, - mockServerPath string, // Path on the mock server for the Chainlink nodes to query - mockServerValue int, // Value to get from the mock server when querying the path + mockAdapter *test_env.Killgrave, + mockAdapterPath string, // Path on the mock server for the Chainlink nodes to query + mockAdapterValue int, // Value to get from the mock server when querying the path chainId uint64, // EVM chain ID forwardingAllowed bool, ) error { @@ -42,12 +43,12 @@ func CreateOCRv2JobsLocal( } p2pV2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PIds.Data[0].Attributes.PeerID, bootstrapNode.InternalIP(), 6690) // Set the value for the jobs to report on - err = mockserver.SetValuePath(mockServerPath, mockServerValue) + err = mockAdapter.SetAdapterBasedIntValuePath(mockAdapterPath, []string{http.MethodGet, http.MethodPost}, mockAdapterValue) if err != nil { return err } // Set the juelsPerFeeCoinSource config value - err = mockserver.SetValuePath(fmt.Sprintf("%s/juelsPerFeeCoinSource", mockServerPath), mockServerValue) + err = mockAdapter.SetAdapterBasedIntValuePath(fmt.Sprintf("%s/juelsPerFeeCoinSource", mockAdapterPath), []string{http.MethodGet, http.MethodPost}, mockAdapterValue) if err != nil { return err } @@ -62,7 +63,7 @@ func CreateOCRv2JobsLocal( RelayConfig: map[string]interface{}{ "chainID": chainId, }, - MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath)), + MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockAdapter.InternalEndpoint, mockAdapterPath)), ContractConfigTrackerPollInterval: *models.NewInterval(15 * time.Second), }, } @@ -83,12 +84,12 @@ func CreateOCRv2JobsLocal( nodeOCRKeyId := nodeOCRKeys.Data[0].ID bta := &client.BridgeTypeAttributes{ - Name: fmt.Sprintf("%s-%s", mockServerPath, uuid.NewString()), - URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath), + Name: fmt.Sprintf("%s-%s", mockAdapterPath, uuid.NewString()), + URL: fmt.Sprintf("%s/%s", mockAdapter.InternalEndpoint, mockAdapterPath), } juelsBridge := &client.BridgeTypeAttributes{ Name: fmt.Sprintf("juels-%s", uuid.NewString()), - URL: fmt.Sprintf("%s/%s/juelsPerFeeCoinSource", mockserver.Config.ClusterURL, mockServerPath), + URL: fmt.Sprintf("%s/%s/juelsPerFeeCoinSource", mockAdapter.InternalEndpoint, mockAdapterPath), } err = chainlinkNode.MustCreateBridge(bta) if err != nil { diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index ae2f3686daf..8bb4e834794 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -3,6 +3,7 @@ package actions import ( "fmt" "math/big" + "net/http" "strings" "github.com/ethereum/go-ethereum" @@ -11,7 +12,7 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -34,7 +35,10 @@ func FundChainlinkNodesLocal( if err != nil { return err } - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress) + gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } @@ -141,7 +145,7 @@ func CreateOCRJobsLocal( bootstrapNode *client.ChainlinkClient, workerNodes []*client.ChainlinkClient, mockValue int, - mockserver *ctfClient.MockserverClient, + mockAdapter *test_env.Killgrave, evmChainID string, ) error { for _, ocrInstance := range ocrInstances { @@ -184,9 +188,9 @@ func CreateOCRJobsLocal( } bta := &client.BridgeTypeAttributes{ Name: nodeContractPairID, - URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, strings.TrimPrefix(nodeContractPairID, "/")), + URL: fmt.Sprintf("%s/%s", mockAdapter.InternalEndpoint, strings.TrimPrefix(nodeContractPairID, "/")), } - err = SetAdapterResponseLocal(mockValue, ocrInstance, node, mockserver) + err = SetAdapterResponseLocal(mockValue, ocrInstance, node, mockAdapter) if err != nil { return fmt.Errorf("setting adapter response for OCR node failed: %w", err) } @@ -234,16 +238,16 @@ func SetAdapterResponseLocal( response int, ocrInstance contracts.OffchainAggregator, chainlinkNode *client.ChainlinkClient, - mockserver *ctfClient.MockserverClient, + mockAdapter *test_env.Killgrave, ) error { nodeContractPairID, err := BuildNodeContractPairIDLocal(chainlinkNode, ocrInstance) if err != nil { return err } path := fmt.Sprintf("/%s", nodeContractPairID) - err = mockserver.SetValuePath(path, response) + err = mockAdapter.SetAdapterBasedIntValuePath(path, []string{http.MethodGet, http.MethodPost}, response) if err != nil { - return fmt.Errorf("setting mockserver value path failed: %w", err) + return fmt.Errorf("setting mock adapter value path failed: %w", err) } return nil } @@ -252,7 +256,7 @@ func SetAllAdapterResponsesToTheSameValueLocal( response int, ocrInstances []contracts.OffchainAggregator, chainlinkNodes []*client.ChainlinkClient, - mockserver *ctfClient.MockserverClient, + mockAdapter *test_env.Killgrave, ) error { eg := &errgroup.Group{} for _, o := range ocrInstances { @@ -260,7 +264,7 @@ func SetAllAdapterResponsesToTheSameValueLocal( for _, n := range chainlinkNodes { node := n eg.Go(func() error { - return SetAdapterResponseLocal(response, ocrInstance, node, mockserver) + return SetAdapterResponseLocal(response, ocrInstance, node, mockAdapter) }) } } @@ -358,7 +362,7 @@ func CreateOCRJobsWithForwarderLocal( bootstrapNode *client.ChainlinkClient, workerNodes []*client.ChainlinkClient, mockValue int, - mockserver *ctfClient.MockserverClient, + mockAdapter *test_env.Killgrave, evmChainID string, ) error { for _, ocrInstance := range ocrInstances { @@ -401,9 +405,9 @@ func CreateOCRJobsWithForwarderLocal( } bta := &client.BridgeTypeAttributes{ Name: nodeContractPairID, - URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, strings.TrimPrefix(nodeContractPairID, "/")), + URL: fmt.Sprintf("%s/%s", mockAdapter.InternalEndpoint, strings.TrimPrefix(nodeContractPairID, "/")), } - err = SetAdapterResponseLocal(mockValue, ocrInstance, node, mockserver) + err = SetAdapterResponseLocal(mockValue, ocrInstance, node, mockAdapter) if err != nil { return err } diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go index b59f8c761f1..24ac217a334 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go @@ -3,13 +3,15 @@ package vrfv2_actions import ( "context" "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" "math/big" "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" vrfConst "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_constants" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -153,9 +155,10 @@ func SetupLocalLoadTestEnv(nodesFunding *big.Float, subFundingLINK *big.Int) (*t env, err := test_env.NewCLTestEnvBuilder(). WithGeth(). WithLogWatcher(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(1). WithFunding(nodesFunding). + WithLogWatcher(). Build() if err != nil { return nil, nil, [32]byte{}, err @@ -209,21 +212,21 @@ func SetupLocalLoadTestEnv(nodesFunding *big.Float, subFundingLINK *big.Int) (*t if err != nil { return nil, nil, [32]byte{}, err } - jobs, err := CreateVRFV2Jobs(env.GetAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) + jobs, err := CreateVRFV2Jobs(env.ClCluster.NodeAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) if err != nil { return nil, nil, [32]byte{}, err } // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - addr, err := env.CLNodes[0].API.PrimaryEthAddress() + addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() if err != nil { return nil, nil, [32]byte{}, err } - nodeConfig := node.NewConfig(env.CLNodes[0].NodeConfig, + nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithVRFv2EVMEstimator(addr), ) - err = env.CLNodes[0].Restart(nodeConfig) + err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { return nil, nil, [32]byte{}, err } diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go new file mode 100644 index 00000000000..7a1221eaf8b --- /dev/null +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go @@ -0,0 +1,42 @@ +package vrfv2plus_config + +import "time" + +type VRFV2PlusConfig struct { + ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with + IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token + LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed + MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"10"` // Amount of LINK to fund the subscription with + SubscriptionFundingAmountNative int64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with + NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request + CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback + MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config + FallbackWeiPerUnitLink int64 `envconfig:"FALLBACK_WEI_PER_UNIT_LINK" default:"60000000000000000"` // Fallback wei per unit LINK for the VRF Coordinator config + StalenessSeconds uint32 `envconfig:"STALENESS_SECONDS" default:"86400"` // Staleness in seconds for the VRF Coordinator config + GasAfterPaymentCalculation uint32 `envconfig:"GAS_AFTER_PAYMENT_CALCULATION" default:"33825"` // Gas after payment calculation for the VRF Coordinator config + FulfillmentFlatFeeLinkPPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM" default:"500"` // Flat fee in ppm for LINK for the VRF Coordinator config + FulfillmentFlatFeeNativePPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_NATIVE_PPM" default:"500"` // Flat fee in ppm for native currency for the VRF Coordinator config + + RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request + RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request + + //Wrapper Config + WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` + CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` + WrapperPremiumPercentage uint8 `envconfig:"WRAPPER_PREMIUM_PERCENTAGE" default:"25"` + WrapperMaxNumberOfWords uint8 `envconfig:"WRAPPER_MAX_NUMBER_OF_WORDS" default:"10"` + WrapperConsumerFundingAmountNativeToken float64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_NATIVE_TOKEN" default:"1"` + WrapperConsumerFundingAmountLink int64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_LINK" default:"10"` + + //LOAD/SOAK Test Config + TestDuration time.Duration `envconfig:"TEST_DURATION" default:"3m"` // How long to run the test for + RPS int64 `envconfig:"RPS" default:"1"` // How many requests per second to send + RateLimitUnitDuration time.Duration `envconfig:"RATE_LIMIT_UNIT_DURATION" default:"1m"` + //Using existing environment and contracts + UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one + CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address + ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address + SubID string `envconfig:"SUB_ID" default:""` // Subscription ID + KeyHash string `envconfig:"KEY_HASH" default:""` +} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go b/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go deleted file mode 100644 index bb266e7c2c5..00000000000 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_constants/constants.go +++ /dev/null @@ -1,40 +0,0 @@ -package vrfv2plus_constants - -import ( - "math/big" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" -) - -var ( - LinkNativeFeedResponse = big.NewInt(1e18) - MinimumConfirmations = uint16(3) - RandomnessRequestCountPerRequest = uint16(1) - VRFSubscriptionFundingAmountLink = big.NewInt(10) - VRFSubscriptionFundingAmountNativeToken = big.NewInt(1) - ChainlinkNodeFundingAmountNative = big.NewFloat(0.1) - NumberOfWords = uint32(3) - CallbackGasLimit = uint32(1000000) - MaxGasLimitVRFCoordinatorConfig = uint32(2.5e6) - StalenessSeconds = uint32(86400) - GasAfterPaymentCalculation = uint32(33825) - - VRFCoordinatorV2_5FeeConfig = vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: 500, - FulfillmentFlatFeeNativePPM: 500, - } - - VRFCoordinatorV2PlusUpgradedVersionFeeConfig = vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ - FulfillmentFlatFeeLinkPPM: 500, - FulfillmentFlatFeeNativePPM: 500, - } - - WrapperGasOverhead = uint32(50_000) - CoordinatorGasOverhead = uint32(52_000) - WrapperPremiumPercentage = uint8(25) - WrapperMaxNumberOfWords = uint8(10) - WrapperConsumerFundingAmountNativeToken = big.NewFloat(1) - - WrapperConsumerFundingAmountLink = big.NewInt(10) -) diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go index 8c3c2a733ac..3bfa5d4f416 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go @@ -4,15 +4,19 @@ import ( "context" "fmt" "math/big" + "sync" "time" + "github.com/smartcontractkit/chainlink/v2/core/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" + "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_constants" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" @@ -229,66 +233,77 @@ func FundVRFCoordinatorV2_5Subscription(linkToken contracts.LinkToken, coordinat return chainClient.WaitForEvents() } +// SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2_5Environment( env *test_env.CLClusterTestEnv, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, - consumerContractsAmount int, -) (*VRFV2_5Contracts, *big.Int, *VRFV2PlusData, error) { + numberOfConsumers int, + numberOfSubToCreate int, +) (*VRFV2_5Contracts, []*big.Int, *VRFV2PlusData, error) { - vrfv2_5Contracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, consumerContractsAmount) + vrfv2_5Contracts, err := DeployVRFV2_5Contracts(env.ContractDeployer, env.EVMClient, numberOfConsumers) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrDeployVRFV2_5Contracts) } err = vrfv2_5Contracts.Coordinator.SetConfig( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.MaxGasLimitVRFCoordinatorConfig, - vrfv2plus_constants.StalenessSeconds, - vrfv2plus_constants.GasAfterPaymentCalculation, - vrfv2plus_constants.LinkNativeFeedResponse, - vrfv2plus_constants.VRFCoordinatorV2_5FeeConfig, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + vrfv2PlusConfig.StalenessSeconds, + vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ + FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + }, ) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrSetVRFCoordinatorConfig) } - subID, err := CreateSubAndFindSubID(env, vrfv2_5Contracts.Coordinator) + err = vrfv2_5Contracts.Coordinator.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, errors.Wrap(err, ErrSetLinkNativeLinkFeed) } - err = env.EVMClient.WaitForEvents() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - for _, consumer := range vrfv2_5Contracts.LoadTestConsumers { - err = vrfv2_5Contracts.Coordinator.AddConsumer(subID, consumer.Address()) - if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrAddConsumerToSub) - } + + subIDs, err := CreateSubsAndFund(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts, numberOfSubToCreate) + if err != nil { + return nil, nil, nil, err } - err = vrfv2_5Contracts.Coordinator.SetLINKAndLINKNativeFeed(linkToken.Address(), mockNativeLINKFeed.Address()) + subToConsumersMap := map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer{} + + //each subscription will have the same consumers + for _, subID := range subIDs { + subToConsumersMap[subID] = vrfv2_5Contracts.LoadTestConsumers + } + + err = AddConsumersToSubs( + subToConsumersMap, + vrfv2_5Contracts.Coordinator, + ) if err != nil { - return nil, nil, nil, errors.Wrap(err, ErrSetLinkNativeLinkFeed) + return nil, nil, nil, err } + err = env.EVMClient.WaitForEvents() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = FundSubscription(env, linkToken, vrfv2_5Contracts.Coordinator, subID) - if err != nil { - return nil, nil, nil, err - } - vrfKey, err := env.GetAPIs()[0].MustCreateVRFKey() + vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrCreatingVRFv2PlusKey) } pubKeyCompressed := vrfKey.Data.ID - nativeTokenPrimaryKeyAddress, err := env.GetAPIs()[0].PrimaryEthAddress() + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrNodePrimaryKey) } @@ -304,12 +319,12 @@ func SetupVRFV2_5Environment( chainID := env.EVMClient.GetChainID() job, err := CreateVRFV2PlusJob( - env.GetAPIs()[0], + env.ClCluster.NodeAPIs()[0], vrfv2_5Contracts.Coordinator.Address(), nativeTokenPrimaryKeyAddress, pubKeyCompressed, chainID.String(), - vrfv2plus_constants.MinimumConfirmations, + vrfv2PlusConfig.MinimumConfirmations, ) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrCreateVRFV2PlusJobs) @@ -318,14 +333,14 @@ func SetupVRFV2_5Environment( // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - addr, err := env.CLNodes[0].API.PrimaryEthAddress() + addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() if err != nil { return nil, nil, nil, errors.Wrap(err, ErrGetPrimaryKey) } - nodeConfig := node.NewConfig(env.CLNodes[0].NodeConfig, + nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithVRFv2EVMEstimator(addr), ) - err = env.CLNodes[0].Restart(nodeConfig) + err = env.ClCluster.Nodes[0].Restart(nodeConfig) if err != nil { return nil, nil, nil, errors.Wrap(err, ErrRestartCLNode) } @@ -343,11 +358,66 @@ func SetupVRFV2_5Environment( chainID, } - return vrfv2_5Contracts, subID, &data, nil + return vrfv2_5Contracts, subIDs, &data, nil +} + +func CreateSubsAndFund( + env *test_env.CLClusterTestEnv, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + linkToken contracts.LinkToken, + vrfv2_5Contracts *VRFV2_5Contracts, + subAmountToCreate int, +) ([]*big.Int, error) { + subs, err := CreateSubs(env, vrfv2_5Contracts.Coordinator, subAmountToCreate) + if err != nil { + return nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, errors.Wrap(err, ErrWaitTXsComplete) + } + err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, vrfv2_5Contracts.Coordinator, subs) + if err != nil { + return nil, err + } + return subs, nil +} + +func CreateSubs( + env *test_env.CLClusterTestEnv, + coordinator contracts.VRFCoordinatorV2_5, + subAmountToCreate int, +) ([]*big.Int, error) { + var subIDArr []*big.Int + + for i := 0; i < subAmountToCreate; i++ { + subID, err := CreateSubAndFindSubID(env, coordinator) + if err != nil { + return nil, err + } + subIDArr = append(subIDArr, subID) + } + return subIDArr, nil +} + +func AddConsumersToSubs( + subToConsumerMap map[*big.Int][]contracts.VRFv2PlusLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2_5, +) error { + for subID, consumers := range subToConsumerMap { + for _, consumer := range consumers { + err := coordinator.AddConsumer(subID, consumer.Address()) + if err != nil { + return errors.Wrap(err, ErrAddConsumerToSub) + } + } + } + return nil } func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, @@ -372,13 +442,16 @@ func SetupVRFV2PlusWrapperEnvironment( if err != nil { return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - vrfv2plus_constants.WrapperGasOverhead, - vrfv2plus_constants.CoordinatorGasOverhead, - vrfv2plus_constants.WrapperPremiumPercentage, + vrfv2PlusConfig.WrapperGasOverhead, + vrfv2PlusConfig.CoordinatorGasOverhead, + vrfv2PlusConfig.WrapperPremiumPercentage, keyHash, - vrfv2plus_constants.WrapperMaxNumberOfWords, + vrfv2PlusConfig.WrapperMaxNumberOfWords, + vrfv2PlusConfig.StalenessSeconds, + big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), + vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, ) if err != nil { return nil, nil, err @@ -400,7 +473,7 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, errors.Wrap(err, ErrWaitTXsComplete) } - err = FundSubscription(env, linkToken, coordinator, wrapperSubID) + err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) if err != nil { return nil, nil, err } @@ -408,7 +481,7 @@ func SetupVRFV2PlusWrapperEnvironment( //fund consumer with Link err = linkToken.Transfer( wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), vrfv2plus_constants.WrapperConsumerFundingAmountLink), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), ) if err != nil { return nil, nil, err @@ -419,7 +492,7 @@ func SetupVRFV2PlusWrapperEnvironment( } //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(vrfv2plus_constants.WrapperConsumerFundingAmountNativeToken) + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) if err != nil { return nil, nil, err } @@ -434,15 +507,17 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts if err != nil { return nil, errors.Wrap(err, ErrCreateVRFSubscription) } - err = env.EVMClient.WaitForEvents() + + sub, err := coordinator.WaitForSubscriptionCreatedEvent(time.Second * 10) if err != nil { - return nil, errors.Wrap(err, ErrWaitTXsComplete) + return nil, errors.Wrap(err, ErrFindSubID) } - subID, err := coordinator.FindSubscriptionID() + + err = env.EVMClient.WaitForEvents() if err != nil { - return nil, errors.Wrap(err, ErrFindSubID) + return nil, errors.Wrap(err, ErrWaitTXsComplete) } - return subID, nil + return sub.SubId, nil } func GetUpgradedCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion) (linkTotalBalance *big.Int, nativeTokenTotalBalance *big.Int, err error) { @@ -469,22 +544,29 @@ func GetCoordinatorTotalBalance(coordinator contracts.VRFCoordinatorV2_5) (linkT return } -func FundSubscription(env *test_env.CLClusterTestEnv, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subID *big.Int) error { - //Native Billing - err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(vrfv2plus_constants.VRFSubscriptionFundingAmountNativeToken, big.NewInt(1e18))) - if err != nil { - return errors.Wrap(err, ErrFundSubWithNativeToken) - } - - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, vrfv2plus_constants.VRFSubscriptionFundingAmountLink) - if err != nil { - return errors.Wrap(err, ErrFundSubWithLinkToken) +func FundSubscriptions( + env *test_env.CLClusterTestEnv, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + linkAddress contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2_5, + subIDs []*big.Int, +) error { + for _, subID := range subIDs { + //Native Billing + err := coordinator.FundSubscriptionWithNative(subID, big.NewInt(0).Mul(big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountNative), big.NewInt(1e18))) + if err != nil { + return errors.Wrap(err, ErrFundSubWithNativeToken) + } + //Link Billing + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, big.NewInt(vrfv2PlusConfig.SubscriptionFundingAmountLink)) + if err != nil { + return errors.Wrap(err, ErrFundSubWithLinkToken) + } } - err = env.EVMClient.WaitForEvents() + err := env.EVMClient.WaitForEvents() if err != nil { return errors.Wrap(err, ErrWaitTXsComplete) } - return nil } @@ -494,22 +576,25 @@ func RequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + randomnessRequestCountPerRequest uint16, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, isNativeBilling, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.NumberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomness) } - return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, l) + return WaitForRequestAndFulfillmentEvents(consumer.Address(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) } func RequestRandomnessAndWaitForFulfillmentUpgraded( @@ -518,16 +603,18 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, isNativeBilling, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomness) @@ -543,15 +630,7 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) } - l.Debug(). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") + LogRandomnessRequestedEventUpgraded(l, coordinator, randomWordsRequestedEvent) randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, @@ -561,14 +640,8 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( if err != nil { return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) } + LogRandomWordsFulfilledEventUpgraded(l, coordinator, randomWordsFulfilledEvent) - l.Debug(). - Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). - Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). - Bool("Success", randomWordsFulfilledEvent.Success). - Msg("RandomWordsFulfilled Event (TX metadata)") return randomWordsFulfilledEvent, err } @@ -578,24 +651,26 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { + logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) if isNativeBilling { _, err := consumer.RequestRandomnessNative( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingNativePayment) } } else { _, err := consumer.RequestRandomness( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.CallbackGasLimit, - vrfv2plus_constants.NumberOfWords, - vrfv2plus_constants.RandomnessRequestCountPerRequest, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.CallbackGasLimit, + vrfv2PlusConfig.NumberOfWords, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, ) if err != nil { return nil, errors.Wrap(err, ErrRequestRandomnessDirectFundingLinkPayment) @@ -605,7 +680,7 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( if err != nil { return nil, errors.Wrap(err, "error getting wrapper address") } - return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, l) + return WaitForRequestAndFulfillmentEvents(wrapperAddress.String(), coordinator, vrfv2PlusData, subID, isNativeBilling, l) } func WaitForRequestAndFulfillmentEvents( @@ -613,6 +688,7 @@ func WaitForRequestAndFulfillmentEvents( coordinator contracts.VRFCoordinatorV2_5, vrfv2PlusData *VRFV2PlusData, subID *big.Int, + isNativeBilling bool, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( @@ -625,15 +701,7 @@ func WaitForRequestAndFulfillmentEvents( return nil, errors.Wrap(err, ErrWaitRandomWordsRequestedEvent) } - l.Debug(). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent, isNativeBilling) randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( []*big.Int{subID}, @@ -644,12 +712,210 @@ func WaitForRequestAndFulfillmentEvents( return nil, errors.Wrap(err, ErrWaitRandomWordsFulfilledEvent) } + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent, isNativeBilling) + return randomWordsFulfilledEvent, err +} + +func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2PlusLoadTestConsumer, timeout time.Duration, wg *sync.WaitGroup) (*big.Int, *big.Int, error) { + metricsChannel := make(chan *contracts.VRFLoadTestMetrics) + metricsErrorChannel := make(chan error) + + testContext, testCancel := context.WithTimeout(context.Background(), timeout) + defer testCancel() + + ticker := time.NewTicker(time.Second * 1) + var metrics *contracts.VRFLoadTestMetrics + for { + select { + case <-testContext.Done(): + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, + fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", + metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) + case <-ticker.C: + go getLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + case metrics = <-metricsChannel: + if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, nil + } + case err := <-metricsErrorChannel: + ticker.Stop() + wg.Done() + return nil, nil, err + } + } +} + +func getLoadTestMetrics( + consumer contracts.VRFv2PlusLoadTestConsumer, + metricsChannel chan *contracts.VRFLoadTestMetrics, + metricsErrorChannel chan error, +) { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + metricsErrorChannel <- err + } + metricsChannel <- metrics +} + +func LogSubDetails(l zerolog.Logger, subscription vrf_coordinator_v2_5.GetSubscription, subID *big.Int, coordinator contracts.VRFCoordinatorV2_5) { l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Link Balance", (*assets.Link)(subscription.Balance).Link()). + Str("Native Token Balance", assets.FormatWei(subscription.NativeBalance)). + Str("Subscription ID", subID.String()). + Str("Subscription Owner", subscription.Owner.String()). + Interface("Subscription Consumers", subscription.Consumers). + Msg("Subscription Data") +} + +func LogRandomnessRequestedEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsRequestedEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEventUpgraded( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, + randomWordsFulfilledEvent *vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). Str("Total Payment in Juels", randomWordsFulfilledEvent.Payment.String()). Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Str("Subscription ID", randomWordsFulfilledEvent.SubID.String()). + Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). + Bool("Success", randomWordsFulfilledEvent.Success). + Msg("RandomWordsFulfilled Event (TX metadata)") +} + +func LogRandomnessRequestedEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsRequestedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, + isNativeBilling bool, +) { + l.Debug(). + Str("Coordinator", coordinator.Address()). + Bool("Native Billing", isNativeBilling). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Str("Subscription ID", randomWordsRequestedEvent.SubId.String()). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2_5, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, + isNativeBilling bool, +) { + l.Debug(). + Bool("Native Billing", isNativeBilling). + Str("Coordinator", coordinator.Address()). + Str("Total Payment", randomWordsFulfilledEvent.Payment.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). Str("Subscription ID", randomWordsFulfilledEvent.SubId.String()). Str("Request ID", randomWordsFulfilledEvent.RequestId.String()). Bool("Success", randomWordsFulfilledEvent.Success). Msg("RandomWordsFulfilled Event (TX metadata)") - return randomWordsFulfilledEvent, err +} + +func LogMigrationCompletedEvent(l zerolog.Logger, migrationCompletedEvent *vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, vrfv2PlusContracts *VRFV2_5Contracts) { + l.Debug(). + Str("Subscription ID", migrationCompletedEvent.SubId.String()). + Str("Migrated From Coordinator", vrfv2PlusContracts.Coordinator.Address()). + Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). + Msg("MigrationCompleted Event") +} + +func LogSubDetailsAfterMigration(l zerolog.Logger, newCoordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, subID *big.Int, migratedSubscription vrf_v2plus_upgraded_version.GetSubscription) { + l.Debug(). + Str("New Coordinator", newCoordinator.Address()). + Str("Subscription ID", subID.String()). + Str("Juels Balance", migratedSubscription.Balance.String()). + Str("Native Token Balance", migratedSubscription.NativeBalance.String()). + Str("Subscription Owner", migratedSubscription.Owner.String()). + Interface("Subscription Consumers", migratedSubscription.Consumers). + Msg("Subscription Data After Migration to New Coordinator") +} + +func LogFulfillmentDetailsLinkBilling( + l zerolog.Logger, + wrapperConsumerJuelsBalanceBeforeRequest *big.Int, + wrapperConsumerJuelsBalanceAfterRequest *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Debug(). + Str("Consumer Balance Before Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceBeforeRequest).Link()). + Str("Consumer Balance After Request (Link)", (*assets.Link)(wrapperConsumerJuelsBalanceAfterRequest).Link()). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract (Link)", (*assets.Link)(consumerStatus.Paid).Link()). + Str("Paid by Coordinator Sub (Link)", (*assets.Link)(randomWordsFulfilledEvent.Payment).Link()). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Fulfilment Details For Link Billing") +} + +func LogFulfillmentDetailsNativeBilling( + l zerolog.Logger, + wrapperConsumerBalanceBeforeRequestWei *big.Int, + wrapperConsumerBalanceAfterRequestWei *big.Int, + consumerStatus vrfv2plus_wrapper_load_test_consumer.GetRequestStatus, + randomWordsFulfilledEvent *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, +) { + l.Debug(). + Str("Consumer Balance Before Request", assets.FormatWei(wrapperConsumerBalanceBeforeRequestWei)). + Str("Consumer Balance After Request", assets.FormatWei(wrapperConsumerBalanceAfterRequestWei)). + Bool("Fulfilment Status", consumerStatus.Fulfilled). + Str("Paid by Consumer Contract", assets.FormatWei(consumerStatus.Paid)). + Str("Paid by Coordinator Sub", assets.FormatWei(randomWordsFulfilledEvent.Payment)). + Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). + Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). + Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). + Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). + Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). + Msg("Random Words Request Fulfilment Details For Native Billing") +} + +func logRandRequest( + consumer string, + coordinator string, + subID *big.Int, + isNativeBilling bool, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + l zerolog.Logger) { + l.Debug(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Str("SubID", subID.String()). + Bool("IsNativePayment", isNativeBilling). + Uint16("MinimumConfirmations", vrfv2PlusConfig.MinimumConfirmations). + Uint32("CallbackGasLimit", vrfv2PlusConfig.CallbackGasLimit). + Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation). + Msg("Requesting randomness") } diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index 59406e51583..a3db60f3b30 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -37,7 +37,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"] [Keeper] @@ -81,7 +80,7 @@ LimitDefault = 5_000_000` }, }, "stateful": true, - "capacity": "1Gi", + "capacity": "10Gi", } soakChainlinkResources = map[string]interface{}{ @@ -108,7 +107,7 @@ LimitDefault = 5_000_000` }, }, "stateful": true, - "capacity": "1Gi", + "capacity": "10Gi", } ) @@ -156,22 +155,22 @@ func TestAutomationBenchmark(t *testing.T) { chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") registryVersions := addRegistry(RegistryToTest) - keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest( + keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest(t, testsetups.KeeperBenchmarkTestInputs{ BlockchainClient: chainClient, RegistryVersions: registryVersions, KeeperRegistrySettings: &contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(0), BlockCountPerTurn: big.NewInt(100), - CheckGasLimit: uint32(45000000), //45M - StalenessSeconds: big.NewInt(90000), + CheckGasLimit: uint32(45_000_000), //45M + StalenessSeconds: big.NewInt(90_000), GasCeilingMultiplier: uint16(2), MaxPerformGas: uint32(MaxPerformGas), MinUpkeepSpend: big.NewInt(0), FallbackGasPrice: big.NewInt(2e11), FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), + MaxCheckDataSize: uint32(5_000), + MaxPerformDataSize: uint32(5_000), }, Upkeeps: &testsetups.UpkeepConfig{ NumberOfUpkeeps: NumberOfUpkeeps, @@ -202,8 +201,8 @@ func TestAutomationBenchmark(t *testing.T) { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) - keeperBenchmarkTest.Setup(t, testEnvironment) - keeperBenchmarkTest.Run(t) + keeperBenchmarkTest.Setup(testEnvironment) + keeperBenchmarkTest.Run() } func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { @@ -316,7 +315,8 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), strings.ReplaceAll(strings.ToLower(RegistryToTest), "_", "-"), ), - Test: t, + Test: t, + PreventPodEviction: true, }) // propagate TEST_INPUTS to remote runner if testEnvironment.WillUseRemoteRunner() { diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 1b18b9f6ab7..6f2cacdb03e 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -37,12 +37,11 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` defaultAutomationSettings = map[string]interface{}{ - "replicas": "6", + "replicas": 6, "toml": client.AddNetworksConfig(baseTOML, networks.SelectedNetwork), "db": map[string]interface{}{ "stateful": true, @@ -111,174 +110,190 @@ func TestAutomationChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - testCases := map[string]struct { - networkChart environment.ConnectedChart - clChart environment.ConnectedChart - chaosFunc chaos.ManifestFunc - chaosProps *chaos.Props - }{ - // see ocr_chaos.test.go for comments - PodChaosFailMinorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), - chaos.NewFailPods, - &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMinority: a.Str("1")}, - DurationStr: "1m", - }, - }, - PodChaosFailMajorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), - chaos.NewFailPods, - &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - DurationStr: "1m", - }, - }, - PodChaosFailMajorityDB: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), - chaos.NewFailPods, - &chaos.Props{ - LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - DurationStr: "1m", - ContainerNames: &[]*string{a.Str("chainlink-db")}, - }, - }, - NetworkChaosFailMajorityNetwork: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), - chaos.NewNetworkPartition, - &chaos.Props{ - FromLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, - ToLabels: &map[string]*string{ChaosGroupMinority: a.Str("1")}, - DurationStr: "1m", - }, - }, - NetworkChaosFailBlockchainNode: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), - chaos.NewNetworkPartition, - &chaos.Props{ - FromLabels: &map[string]*string{"app": a.Str("geth")}, - ToLabels: &map[string]*string{ChaosGroupMajorityPlus: a.Str("1")}, - DurationStr: "1m", - }, - }, + registryVersions := map[string]eth_contracts.KeeperRegistryVersion{ + "registry_2_0": eth_contracts.RegistryVersion_2_0, + "registry_2_1": eth_contracts.RegistryVersion_2_1, } - for n, tst := range testCases { - name := n - testCase := tst - t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { + for name, registryVersion := range registryVersions { + t.Run(name, func(t *testing.T) { t.Parallel() - network := networks.SelectedNetwork // Need a new copy of the network for each test - - testEnvironment := environment. - New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("chaos-automation-%s", name), - TTL: time.Hour * 1, - Test: t, - }). - AddHelm(testCase.networkChart). - AddHelm(testCase.clChart). - AddChart(blockscout.New(&blockscout.Props{ - Name: "geth-blockscout", - WsURL: network.URL, - HttpURL: network.HTTPURLs[0], - })) - err := testEnvironment.Run() - require.NoError(t, err, "Error setting up test environment") - if testEnvironment.WillUseRemoteRunner() { - return + + testCases := map[string]struct { + networkChart environment.ConnectedChart + clChart environment.ConnectedChart + chaosFunc chaos.ManifestFunc + chaosProps *chaos.Props + }{ + // see ocr_chaos.test.go for comments + PodChaosFailMinorityNodes: { + ethereum.New(defaultEthereumSettings), + chainlink.New(0, defaultAutomationSettings), + chaos.NewFailPods, + &chaos.Props{ + LabelsSelector: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + DurationStr: "1m", + }, + }, + PodChaosFailMajorityNodes: { + ethereum.New(defaultEthereumSettings), + chainlink.New(0, defaultAutomationSettings), + chaos.NewFailPods, + &chaos.Props{ + LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + DurationStr: "1m", + }, + }, + PodChaosFailMajorityDB: { + ethereum.New(defaultEthereumSettings), + chainlink.New(0, defaultAutomationSettings), + chaos.NewFailPods, + &chaos.Props{ + LabelsSelector: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + DurationStr: "1m", + ContainerNames: &[]*string{a.Str("chainlink-db")}, + }, + }, + NetworkChaosFailMajorityNetwork: { + ethereum.New(defaultEthereumSettings), + chainlink.New(0, defaultAutomationSettings), + chaos.NewNetworkPartition, + &chaos.Props{ + FromLabels: &map[string]*string{ChaosGroupMajority: a.Str("1")}, + ToLabels: &map[string]*string{ChaosGroupMinority: a.Str("1")}, + DurationStr: "1m", + }, + }, + NetworkChaosFailBlockchainNode: { + ethereum.New(defaultEthereumSettings), + chainlink.New(0, defaultAutomationSettings), + chaos.NewNetworkPartition, + &chaos.Props{ + FromLabels: &map[string]*string{"app": a.Str("geth")}, + ToLabels: &map[string]*string{ChaosGroupMajorityPlus: a.Str("1")}, + DurationStr: "1m", + }, + }, + } + + for n, tst := range testCases { + name := n + testCase := tst + t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { + t.Parallel() + network := networks.SelectedNetwork // Need a new copy of the network for each test + + testEnvironment := environment. + New(&environment.Config{ + NamespacePrefix: fmt.Sprintf("chaos-automation-%s", name), + TTL: time.Hour * 1, + Test: t, + }). + AddHelm(testCase.networkChart). + AddHelm(testCase.clChart). + AddChart(blockscout.New(&blockscout.Props{ + Name: "geth-blockscout", + WsURL: network.URL, + HttpURL: network.HTTPURLs[0], + })) + err := testEnvironment.Run() + require.NoError(t, err, "Error setting up test environment") + if testEnvironment.WillUseRemoteRunner() { + return + } + + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 1, 2, ChaosGroupMinority) + require.NoError(t, err) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 3, 5, ChaosGroupMajority) + require.NoError(t, err) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 2, 5, ChaosGroupMajorityPlus) + require.NoError(t, err) + + chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) + require.NoError(t, err, "Error connecting to blockchain") + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) + require.NoError(t, err, "Error building contract deployer") + + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) + require.NoError(t, err, "Error connecting to Chainlink nodes") + chainClient.ParallelTransactions(true) + + // Register cleanup for any test + t.Cleanup(func() { + if chainClient != nil { + chainClient.GasStats().PrintStats() + } + err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + require.NoError(t, err, "Error tearing down environment") + }) + + txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) + require.NoError(t, err, "Error estimating cost for Chainlink Operations") + err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) + require.NoError(t, err, "Error funding Chainlink nodes") + + linkToken, err := contractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Error deploying LINK token") + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, + registryVersion, + defaultOCRRegistryConfig, + linkToken, + contractDeployer, + chainClient, + ) + + // Fund the registry with LINK + err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(numberOfUpkeeps)))) + require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + + actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, registryVersion) + nodesWithoutBootstrap := chainlinkNodes[1:] + ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, defaultOCRRegistryConfig, registrar.Address(), 30*time.Second) + require.NoError(t, err, "Error building OCR config vars") + err = registry.SetConfig(defaultOCRRegistryConfig, ocrConfig) + require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") + + consumers_conditional, upkeepIDs_conditional := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false, false) + consumers_logtrigger, upkeepIDs_logtrigger := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, true, false) + + consumers := append(consumers_conditional, consumers_logtrigger...) + upkeepIDs := append(upkeepIDs_conditional, upkeepIDs_logtrigger...) + + l.Info().Msg("Waiting for all upkeeps to be performed") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 5 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + + _, err = testEnvironment.Chaos.Run(testCase.chaosFunc(testEnvironment.Cfg.Namespace, testCase.chaosProps)) + require.NoError(t, err) + + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 10 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "3m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + }) } - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 1, 2, ChaosGroupMinority) - require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 3, 5, ChaosGroupMajority) - require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 2, 5, ChaosGroupMajorityPlus) - require.NoError(t, err) - - chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - chainClient.ParallelTransactions(true) - - // Register cleanup for any test - t.Cleanup(func() { - if chainClient != nil { - chainClient.GasStats().PrintStats() - } - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") - }) - - txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) - require.NoError(t, err, "Error estimating cost for Chainlink Operations") - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) - require.NoError(t, err, "Error funding Chainlink nodes") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying LINK token") - - registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( - t, - eth_contracts.RegistryVersion_2_0, - defaultOCRRegistryConfig, - linkToken, - contractDeployer, - chainClient, - ) - - // Fund the registry with LINK - err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(numberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - - actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, eth_contracts.RegistryVersion_2_0) - nodesWithoutBootstrap := chainlinkNodes[1:] - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, defaultOCRRegistryConfig, registrar.Address(), 30*time.Second) - require.NoError(t, err, "Error building OCR config vars") - err = registry.SetConfig(defaultOCRRegistryConfig, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") - require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") - - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false) - - l.Info().Msg("Waiting for all upkeeps to be performed") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - expect := 5 - l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), - "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) - } - }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer - - _, err = testEnvironment.Chaos.Run(testCase.chaosFunc(testEnvironment.Cfg.Namespace, testCase.chaosProps)) - require.NoError(t, err) - - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 10 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - expect := 10 - l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), - "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) - } - }, "3m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer }) } } diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index fd51fa55db5..1d7f61f783c 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -34,7 +34,7 @@ func TestOCR2VRFChaos(t *testing.T) { loadedNetwork := networks.SelectedNetwork defaultOCR2VRFSettings := map[string]interface{}{ - "replicas": "6", + "replicas": 6, "toml": client.AddNetworkDetailedConfig( config.BaseOCR2Config, config.DefaultOCR2VRFNetworkDetailTomlConfig, @@ -135,9 +135,9 @@ func TestOCR2VRFChaos(t *testing.T) { return } - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 1, 2, ChaosGroupMinority) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 1, 2, ChaosGroupMinority) require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 3, 5, ChaosGroupMajority) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 3, 5, ChaosGroupMajority) require.NoError(t, err) chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index 569a0d1b70c..f3ee12046fb 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -32,7 +32,7 @@ import ( var ( defaultOCRSettings = map[string]interface{}{ - "replicas": "6", + "replicas": 6, "db": map[string]interface{}{ "stateful": true, "capacity": "1Gi", @@ -146,11 +146,11 @@ func TestOCRChaos(t *testing.T) { return } - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 1, 2, ChaosGroupMinority) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 1, 2, ChaosGroupMinority) require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 3, 5, ChaosGroupMajority) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 3, 5, ChaosGroupMajority) require.NoError(t, err) - err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=", 2, 5, ChaosGroupMajorityPlus) + err = testEnvironment.Client.LabelChaosGroup(testEnvironment.Cfg.Namespace, "instance=node-", 2, 5, ChaosGroupMajorityPlus) require.NoError(t, err) chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment, l) diff --git a/integration-tests/config/config.go b/integration-tests/config/config.go index cd3f5983a28..44c108b0d7f 100644 --- a/integration-tests/config/config.go +++ b/integration-tests/config/config.go @@ -4,6 +4,10 @@ var ( BaseOCRP2PV1Config = `[OCR] Enabled = true +[P2P] +[P2P.V2] +Enabled = false + [P2P] [P2P.V1] Enabled = true @@ -18,7 +22,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` @@ -67,7 +70,6 @@ CaptureEATelemetry = true [P2P] [P2P.V2] -Enabled = true ListenAddresses = ['0.0.0.0:6690']` TelemetryIngressConfig = `[TelemetryIngress] diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index dcf81edede7..bdf63d19195 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -11,12 +11,12 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_v1_events_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" @@ -29,6 +29,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/gas_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/gas_wrapper_mock" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_performance_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registrar_wrapper1_2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registrar_wrapper1_2_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registrar_wrapper2_0" @@ -43,14 +45,26 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" registry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_aggregator_proxy" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_ethlink_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_gas_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/perform_data_checker_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_upkeep_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_counter_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" + + eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) // ContractDeployer is an interface for abstracting the contract deployment methods across network implementations @@ -60,6 +74,7 @@ type ContractDeployer interface { DeployFlags(rac string) (Flags, error) DeployFluxAggregatorContract(linkAddr string, fluxOptions FluxAggregatorOptions) (FluxAggregator, error) DeployLinkTokenContract() (LinkToken, error) + DeployWERC20Mock() (WERC20Mock, error) LoadLinkToken(address common.Address) (LinkToken, error) DeployOffChainAggregator(linkAddr string, offchainOptions OffchainOptions) (OffchainAggregator, error) LoadOffChainAggregator(address *common.Address) (OffchainAggregator, error) @@ -75,6 +90,8 @@ type ContractDeployer interface { LoadKeeperRegistry(address common.Address, registryVersion eth_contracts.KeeperRegistryVersion) (KeeperRegistry, error) DeployKeeperConsumer(updateInterval *big.Int) (KeeperConsumer, error) DeployAutomationLogTriggerConsumer(testInterval *big.Int) (KeeperConsumer, error) + DeployAutomationStreamsLookupUpkeepConsumer(testRange *big.Int, interval *big.Int, useArbBlock bool, staging bool, verify bool) (KeeperConsumer, error) + DeployAutomationLogTriggeredStreamsLookupUpkeepConsumer() (KeeperConsumer, error) DeployKeeperConsumerPerformance( testBlockRange, averageCadence, @@ -117,6 +134,10 @@ type ContractDeployer interface { DeployKeeperRegistry11Mock() (KeeperRegistry11Mock, error) DeployKeeperRegistrar12Mock() (KeeperRegistrar12Mock, error) DeployKeeperGasWrapperMock() (KeeperGasWrapperMock, error) + DeployMercuryVerifierContract(verifierProxyAddr common.Address) (MercuryVerifier, error) + DeployMercuryVerifierProxyContract(accessControllerAddr common.Address) (MercuryVerifierProxy, error) + DeployMercuryFeeManager(linkAddress common.Address, nativeAddress common.Address, proxyAddress common.Address, rewardManagerAddress common.Address) (MercuryFeeManager, error) + DeployMercuryRewardManager(linkAddress common.Address) (MercuryRewardManager, error) } // NewContractDeployer returns an instance of a contract deployer based on the client type @@ -144,6 +165,10 @@ func NewContractDeployer(bcClient blockchain.EVMClient, logger zerolog.Logger) ( return &BSCContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil case *blockchain.ScrollClient: return &ScrollContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.PolygonZkEvmClient: + return &PolygonZkEvmContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil + case *blockchain.LineaClient: + return &LineaContractDeployer{NewEthereumContractDeployer(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract deployer, register blockchain client in NewContractDeployer") } @@ -199,6 +224,14 @@ type ScrollContractDeployer struct { *EthereumContractDeployer } +type PolygonZkEvmContractDeployer struct { + *EthereumContractDeployer +} + +type LineaContractDeployer struct { + *EthereumContractDeployer +} + // NewEthereumContractDeployer returns an instantiated instance of the ETH contract deployer func NewEthereumContractDeployer(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractDeployer { return &EthereumContractDeployer{ @@ -737,8 +770,10 @@ func (e *EthereumContractDeployer) DeployKeeperRegistrar(registryVersion eth_con ) (common.Address, *types.Transaction, interface{}, error) { // set default TriggerType to 0(conditional), AutoApproveConfigType to 2(auto approve enabled), AutoApproveMaxAllowed to 1000 triggerConfigs := []registrar21.AutomationRegistrar21InitialTriggerConfig{ - {TriggerType: 0, AutoApproveType: 2, AutoApproveMaxAllowed: 1000}, - {TriggerType: 1, AutoApproveType: 2, AutoApproveMaxAllowed: 1000}, + {TriggerType: 0, AutoApproveType: registrarSettings.AutoApproveConfigType, + AutoApproveMaxAllowed: uint32(registrarSettings.AutoApproveMaxAllowed)}, + {TriggerType: 1, AutoApproveType: registrarSettings.AutoApproveConfigType, + AutoApproveMaxAllowed: uint32(registrarSettings.AutoApproveMaxAllowed)}, } return registrar21.DeployAutomationRegistrar( @@ -1198,14 +1233,14 @@ func (e *EthereumContractDeployer) DeployKeeperConsumer(updateInterval *big.Int) auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployKeeperConsumer(auth, backend, updateInterval) + return keeper_consumer_wrapper.DeployKeeperConsumer(auth, backend, updateInterval) }) if err != nil { return nil, err } return &EthereumKeeperConsumer{ client: e.client, - consumer: instance.(*eth_contracts.KeeperConsumer), + consumer: instance.(*keeper_consumer_wrapper.KeeperConsumer), address: address, }, err } @@ -1229,19 +1264,57 @@ func (e *EthereumContractDeployer) DeployAutomationLogTriggerConsumer(testInterv }, err } +func (e *EthereumContractDeployer) DeployAutomationStreamsLookupUpkeepConsumer(testRange *big.Int, interval *big.Int, useArbBlock bool, staging bool, verify bool) (KeeperConsumer, error) { + address, _, instance, err := e.client.DeployContract("StreamsLookupUpkeep", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return streams_lookup_upkeep_wrapper.DeployStreamsLookupUpkeep( + auth, backend, testRange, interval, useArbBlock, staging, verify, + ) + }) + if err != nil { + return nil, err + } + return &EthereumAutomationStreamsLookupUpkeepConsumer{ + client: e.client, + consumer: instance.(*streams_lookup_upkeep_wrapper.StreamsLookupUpkeep), + address: address, + }, err +} + +func (e *EthereumContractDeployer) DeployAutomationLogTriggeredStreamsLookupUpkeepConsumer() (KeeperConsumer, error) { + address, _, instance, err := e.client.DeployContract("LogTriggeredStreamsLookupUpkeep", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return log_triggered_streams_lookup_wrapper.DeployLogTriggeredStreamsLookup( + auth, backend, false, false, + ) + }) + if err != nil { + return nil, err + } + return &EthereumAutomationLogTriggeredStreamsLookupUpkeepConsumer{ + client: e.client, + consumer: instance.(*log_triggered_streams_lookup_wrapper.LogTriggeredStreamsLookup), + address: address, + }, err +} + func (e *EthereumContractDeployer) DeployUpkeepCounter(testRange *big.Int, interval *big.Int) (UpkeepCounter, error) { address, _, instance, err := e.client.DeployContract("UpkeepCounter", func( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployUpkeepCounter(auth, backend, testRange, interval) + return upkeep_counter_wrapper.DeployUpkeepCounter(auth, backend, testRange, interval) }) if err != nil { return nil, err } return &EthereumUpkeepCounter{ client: e.client, - consumer: instance.(*eth_contracts.UpkeepCounter), + consumer: instance.(*upkeep_counter_wrapper.UpkeepCounter), address: address, }, err } @@ -1251,14 +1324,14 @@ func (e *EthereumContractDeployer) DeployUpkeepPerformCounterRestrictive(testRan auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployUpkeepPerformCounterRestrictive(auth, backend, testRange, averageEligibilityCadence) + return upkeep_perform_counter_restrictive_wrapper.DeployUpkeepPerformCounterRestrictive(auth, backend, testRange, averageEligibilityCadence) }) if err != nil { return nil, err } return &EthereumUpkeepPerformCounterRestrictive{ client: e.client, - consumer: instance.(*eth_contracts.UpkeepPerformCounterRestrictive), + consumer: instance.(*upkeep_perform_counter_restrictive_wrapper.UpkeepPerformCounterRestrictive), address: address, }, err } @@ -1273,7 +1346,7 @@ func (e *EthereumContractDeployer) DeployKeeperConsumerPerformance( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployKeeperConsumerPerformance( + return keeper_consumer_performance_wrapper.DeployKeeperConsumerPerformance( auth, backend, testBlockRange, @@ -1287,7 +1360,7 @@ func (e *EthereumContractDeployer) DeployKeeperConsumerPerformance( } return &EthereumKeeperConsumerPerformance{ client: e.client, - consumer: instance.(*eth_contracts.KeeperConsumerPerformance), + consumer: instance.(*keeper_consumer_performance_wrapper.KeeperConsumerPerformance), address: address, }, err } @@ -1335,7 +1408,7 @@ func (e *EthereumContractDeployer) DeployKeeperPerformDataChecker(expectedData [ auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployPerformDataChecker( + return perform_data_checker_wrapper.DeployPerformDataChecker( auth, backend, expectedData, @@ -1346,7 +1419,7 @@ func (e *EthereumContractDeployer) DeployKeeperPerformDataChecker(expectedData [ } return &EthereumKeeperPerformDataCheckerConsumer{ client: e.client, - performDataChecker: instance.(*eth_contracts.PerformDataChecker), + performDataChecker: instance.(*perform_data_checker_wrapper.PerformDataChecker), address: address, }, err } @@ -1436,3 +1509,93 @@ func (e *EthereumContractDeployer) DeployOffchainAggregatorV2( l: e.l, }, err } + +func (e *EthereumContractDeployer) DeployMercuryVerifierContract(verifierProxyAddr common.Address) (MercuryVerifier, error) { + address, _, instance, err := e.client.DeployContract("Mercury Verifier", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return verifier.DeployVerifier(auth, backend, verifierProxyAddr) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifier{ + client: e.client, + instance: instance.(*verifier.Verifier), + address: *address, + l: e.l, + }, err +} + +func (e *EthereumContractDeployer) DeployMercuryVerifierProxyContract(accessControllerAddr common.Address) (MercuryVerifierProxy, error) { + address, _, instance, err := e.client.DeployContract("Mercury Verifier Proxy", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return verifier_proxy.DeployVerifierProxy(auth, backend, accessControllerAddr) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryVerifierProxy{ + client: e.client, + instance: instance.(*verifier_proxy.VerifierProxy), + address: *address, + l: e.l, + }, err +} + +func (e *EthereumContractDeployer) DeployMercuryFeeManager(linkAddress common.Address, nativeAddress common.Address, proxyAddress common.Address, rewardManagerAddress common.Address) (MercuryFeeManager, error) { + address, _, instance, err := e.client.DeployContract("Mercury Fee Manager", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return fee_manager.DeployFeeManager(auth, backend, linkAddress, nativeAddress, proxyAddress, rewardManagerAddress) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryFeeManager{ + client: e.client, + instance: instance.(*fee_manager.FeeManager), + address: *address, + l: e.l, + }, err +} + +func (e *EthereumContractDeployer) DeployMercuryRewardManager(linkAddress common.Address) (MercuryRewardManager, error) { + address, _, instance, err := e.client.DeployContract("Mercury Reward Manager", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return reward_manager.DeployRewardManager(auth, backend, linkAddress) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryRewardManager{ + client: e.client, + instance: instance.(*reward_manager.RewardManager), + address: *address, + l: e.l, + }, err +} + +func (e *EthereumContractDeployer) DeployWERC20Mock() (WERC20Mock, error) { + address, _, instance, err := e.client.DeployContract("WERC20 Mock", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return werc20_mock.DeployWERC20Mock(auth, backend) + }) + if err != nil { + return nil, err + } + return &EthereumWERC20Mock{ + client: e.client, + instance: instance.(*werc20_mock.WERC20Mock), + address: *address, + l: e.l, + }, err +} diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index a790747e38d..4dda2d3f0c4 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -2,6 +2,8 @@ package contracts import ( "errors" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -14,8 +16,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" ) // ContractLoader is an interface for abstracting the contract loading methods across network implementations @@ -30,8 +35,16 @@ type ContractLoader interface { LoadFunctionsLoadTestClient(addr string) (FunctionsLoadTestClient, error) // Mercury - LoadMercuryVerifier(addr string) (MercuryVerifier, error) - LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) + LoadMercuryVerifier(addr common.Address) (MercuryVerifier, error) + LoadMercuryVerifierProxy(addr common.Address) (MercuryVerifierProxy, error) + LoadMercuryFeeManager(addr common.Address) (MercuryFeeManager, error) + LoadMercuryRewardManager(addr common.Address) (MercuryRewardManager, error) + + LoadWERC20Mock(addr common.Address) (WERC20Mock, error) + + // VRF + LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) + LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) } // NewContractLoader returns an instance of a contract Loader based on the client type @@ -49,6 +62,8 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &PolygonContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.OptimismClient: return &OptimismContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.PolygonZkEvmClient: + return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -83,6 +98,14 @@ type PolygonContractLoader struct { type OptimismContractLoader struct { *EthereumContractLoader } +type PolygonZkEvmContractLoader struct { + *EthereumContractLoader +} + +// PolygonZKEVMContractLoader wraps for Polygon zkEVM +type PolygonZKEVMContractLoader struct { + *EthereumContractLoader +} // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { @@ -204,8 +227,8 @@ func (e *EthereumContractLoader) LoadAuthorizedForwarder(address common.Address) } // LoadMercuryVerifier returns Verifier contract deployed on given address -func (e *EthereumContractLoader) LoadMercuryVerifier(addr string) (MercuryVerifier, error) { - instance, err := e.client.LoadContract("Mercury Verifier", common.HexToAddress(addr), func( +func (e *EthereumContractLoader) LoadMercuryVerifier(addr common.Address) (MercuryVerifier, error) { + instance, err := e.client.LoadContract("Mercury Verifier", addr, func( address common.Address, backend bind.ContractBackend, ) (interface{}, error) { @@ -217,13 +240,13 @@ func (e *EthereumContractLoader) LoadMercuryVerifier(addr string) (MercuryVerifi return &EthereumMercuryVerifier{ client: e.client, instance: instance.(*verifier.Verifier), - address: common.HexToAddress(addr), + address: addr, }, err } // LoadMercuryVerifierProxy returns VerifierProxy contract deployed on given address -func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr string) (MercuryVerifierProxy, error) { - instance, err := e.client.LoadContract("Mercury Verifier Proxy", common.HexToAddress(addr), func( +func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr common.Address) (MercuryVerifierProxy, error) { + instance, err := e.client.LoadContract("Mercury Verifier Proxy", addr, func( address common.Address, backend bind.ContractBackend, ) (interface{}, error) { @@ -235,6 +258,93 @@ func (e *EthereumContractLoader) LoadMercuryVerifierProxy(addr string) (MercuryV return &EthereumMercuryVerifierProxy{ client: e.client, instance: instance.(*verifier_proxy.VerifierProxy), - address: common.HexToAddress(addr), + address: addr, + }, err +} + +func (e *EthereumContractLoader) LoadMercuryFeeManager(addr common.Address) (MercuryFeeManager, error) { + instance, err := e.client.LoadContract("Mercury Fee Manager", addr, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return fee_manager.NewFeeManager(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryFeeManager{ + client: e.client, + instance: instance.(*fee_manager.FeeManager), + address: addr, + }, err +} + +func (e *EthereumContractLoader) LoadMercuryRewardManager(addr common.Address) (MercuryRewardManager, error) { + instance, err := e.client.LoadContract("Mercury Reward Manager", addr, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return reward_manager.NewRewardManager(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumMercuryRewardManager{ + client: e.client, + instance: instance.(*reward_manager.RewardManager), + address: addr, + }, err +} + +func (e *EthereumContractLoader) LoadWERC20Mock(addr common.Address) (WERC20Mock, error) { + instance, err := e.client.LoadContract("WERC20 Mock", addr, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return werc20_mock.NewWERC20Mock(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumWERC20Mock{ + client: e.client, + instance: instance.(*werc20_mock.WERC20Mock), + address: addr, + }, err +} + +func (e *EthereumContractLoader) LoadVRFCoordinatorV2_5(addr string) (VRFCoordinatorV2_5, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFCoordinatorV2_5", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_coordinator_v2_5.NewVRFCoordinatorV25(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFCoordinatorV2_5{ + address: &address, + client: e.client, + coordinator: instance.(*vrf_coordinator_v2_5.VRFCoordinatorV25), + }, err +} + +func (e *EthereumContractLoader) LoadVRFv2PlusLoadTestConsumer(addr string) (VRFv2PlusLoadTestConsumer, error) { + address := common.HexToAddress(addr) + instance, err := e.client.LoadContract("VRFV2PlusLoadTestWithMetrics", address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return vrf_v2plus_load_test_with_metrics.NewVRFV2PlusLoadTestWithMetrics(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumVRFv2PlusLoadTestConsumer{ + client: e.client, + consumer: instance.(*vrf_v2plus_load_test_with_metrics.VRFV2PlusLoadTestWithMetrics), + address: &address, }, err } diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 9f1130dce9f..51fce7cb120 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/functions_billing_registry_events_mock" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" ) type FluxAggregatorOptions struct { @@ -369,12 +370,33 @@ type FunctionsLoadTestClient interface { } type MercuryVerifier interface { - Address() string + Address() common.Address Verify(signedReport []byte, sender common.Address) error + SetConfig(feedId [32]byte, signers []common.Address, offchainTransmitters [][32]byte, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte, recipientAddressesAndWeights []verifier.CommonAddressAndWeight) (*types.Transaction, error) + LatestConfigDetails(ctx context.Context, feedId [32]byte) (verifier.LatestConfigDetails, error) } type MercuryVerifierProxy interface { - Address() string + Address() common.Address + InitializeVerifier(verifierAddress common.Address) (*types.Transaction, error) Verify(signedReport []byte, parameterPayload []byte, value *big.Int) (*types.Transaction, error) VerifyBulk(signedReports [][]byte, parameterPayload []byte, value *big.Int) (*types.Transaction, error) + SetFeeManager(feeManager common.Address) (*types.Transaction, error) +} + +type MercuryFeeManager interface { + Address() common.Address +} + +type MercuryRewardManager interface { + Address() common.Address + SetFeeManager(feeManager common.Address) (*types.Transaction, error) +} + +type WERC20Mock interface { + Address() common.Address + BalanceOf(ctx context.Context, addr string) (*big.Int, error) + Approve(to string, amount *big.Int) error + Transfer(to string, amount *big.Int) error + Mint(account common.Address, amount *big.Int) (*types.Transaction, error) } diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 0d302215bea..656cabb92e9 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -2,20 +2,19 @@ package contracts import ( "context" - "math/big" "time" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" ) @@ -85,6 +84,7 @@ type VRFCoordinatorV2_5 interface { GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) FindSubscriptionID() (*big.Int, error) + WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested, error) WaitForMigrationCompletedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25MigrationCompleted, error) @@ -126,7 +126,7 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { type VRFV2PlusWrapper interface { Address() string - SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error + SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32) error GetSubID(ctx context.Context) (*big.Int, error) } @@ -153,7 +153,7 @@ type VRFConsumerV2 interface { type VRFv2Consumer interface { Address() string RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32) error - GetRequestStatus(ctx context.Context, requestID *big.Int) (RequestStatus, error) + GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) GetLastRequestId(ctx context.Context) (*big.Int, error) } @@ -172,6 +172,7 @@ type VRFv2PlusLoadTestConsumer interface { GetLastRequestId(ctx context.Context) (*big.Int, error) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) GetCoordinator(ctx context.Context) (common.Address, error) + ResetMetrics() error } type VRFv2PlusWrapperLoadTestConsumer interface { diff --git a/integration-tests/contracts/ethereum/KeeperConsumer.go b/integration-tests/contracts/ethereum/KeeperConsumer.go deleted file mode 100644 index c0691729d21..00000000000 --- a/integration-tests/contracts/ethereum/KeeperConsumer.go +++ /dev/null @@ -1,361 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethereum - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// KeeperConsumerMetaData contains all meta data concerning the KeeperConsumer contract. -var KeeperConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"updateInterval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"upkeepNeeded\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastTimeStamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b506040516103583803806103588339818101604052602081101561003357600080fd5b505160805242600155600080556080516102fe61005a6000398061025452506102fe6000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633f3b3b271461005c5780634585e33b1461007657806361bc221a146100e65780636e04ff0d146100ee578063947a36fb146101dd575b600080fd5b6100646101e5565b60408051918252519081900360200190f35b6100e46004803603602081101561008c57600080fd5b810190602081018135600160201b8111156100a657600080fd5b8201836020820111156100b857600080fd5b803590602001918460018302840111600160201b831117156100d957600080fd5b5090925090506101eb565b005b6100646101f8565b61015c6004803603602081101561010457600080fd5b810190602081018135600160201b81111561011e57600080fd5b82018360208201111561013057600080fd5b803590602001918460018302840111600160201b8311171561015157600080fd5b5090925090506101fe565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101a1578181015183820152602001610189565b50505050905090810190601f1680156101ce5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b610064610252565b60015481565b5050600080546001019055565b60005481565b6000606061020a610276565b6001848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b32156102c6576040805162461bcd60e51b815260206004820152601a6024820152791bdb9b1e48199bdc881cda5b5d5b185d195908189858dad95b9960321b604482015290519081900360640190fd5b56fea2646970667358221220c0e089efa59b00d8b131c6b0456904c0ef8f5646c27f81de540a4cc400cff70c64736f6c63430007060033", -} - -// KeeperConsumerABI is the input ABI used to generate the binding from. -// Deprecated: Use KeeperConsumerMetaData.ABI instead. -var KeeperConsumerABI = KeeperConsumerMetaData.ABI - -// KeeperConsumerBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use KeeperConsumerMetaData.Bin instead. -var KeeperConsumerBin = KeeperConsumerMetaData.Bin - -// DeployKeeperConsumer deploys a new Ethereum contract, binding an instance of KeeperConsumer to it. -func DeployKeeperConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, updateInterval *big.Int) (common.Address, *types.Transaction, *KeeperConsumer, error) { - parsed, err := KeeperConsumerMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(KeeperConsumerBin), backend, updateInterval) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &KeeperConsumer{KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil -} - -// KeeperConsumer is an auto generated Go binding around an Ethereum contract. -type KeeperConsumer struct { - KeeperConsumerCaller // Read-only binding to the contract - KeeperConsumerTransactor // Write-only binding to the contract - KeeperConsumerFilterer // Log filterer for contract events -} - -// KeeperConsumerCaller is an auto generated read-only Go binding around an Ethereum contract. -type KeeperConsumerCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// KeeperConsumerTransactor is an auto generated write-only Go binding around an Ethereum contract. -type KeeperConsumerTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// KeeperConsumerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type KeeperConsumerFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// KeeperConsumerSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type KeeperConsumerSession struct { - Contract *KeeperConsumer // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// KeeperConsumerCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type KeeperConsumerCallerSession struct { - Contract *KeeperConsumerCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// KeeperConsumerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type KeeperConsumerTransactorSession struct { - Contract *KeeperConsumerTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// KeeperConsumerRaw is an auto generated low-level Go binding around an Ethereum contract. -type KeeperConsumerRaw struct { - Contract *KeeperConsumer // Generic contract binding to access the raw methods on -} - -// KeeperConsumerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type KeeperConsumerCallerRaw struct { - Contract *KeeperConsumerCaller // Generic read-only contract binding to access the raw methods on -} - -// KeeperConsumerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type KeeperConsumerTransactorRaw struct { - Contract *KeeperConsumerTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewKeeperConsumer creates a new instance of KeeperConsumer, bound to a specific deployed contract. -func NewKeeperConsumer(address common.Address, backend bind.ContractBackend) (*KeeperConsumer, error) { - contract, err := bindKeeperConsumer(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &KeeperConsumer{KeeperConsumerCaller: KeeperConsumerCaller{contract: contract}, KeeperConsumerTransactor: KeeperConsumerTransactor{contract: contract}, KeeperConsumerFilterer: KeeperConsumerFilterer{contract: contract}}, nil -} - -// NewKeeperConsumerCaller creates a new read-only instance of KeeperConsumer, bound to a specific deployed contract. -func NewKeeperConsumerCaller(address common.Address, caller bind.ContractCaller) (*KeeperConsumerCaller, error) { - contract, err := bindKeeperConsumer(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &KeeperConsumerCaller{contract: contract}, nil -} - -// NewKeeperConsumerTransactor creates a new write-only instance of KeeperConsumer, bound to a specific deployed contract. -func NewKeeperConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*KeeperConsumerTransactor, error) { - contract, err := bindKeeperConsumer(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &KeeperConsumerTransactor{contract: contract}, nil -} - -// NewKeeperConsumerFilterer creates a new log filterer instance of KeeperConsumer, bound to a specific deployed contract. -func NewKeeperConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*KeeperConsumerFilterer, error) { - contract, err := bindKeeperConsumer(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &KeeperConsumerFilterer{contract: contract}, nil -} - -// bindKeeperConsumer binds a generic wrapper to an already deployed contract. -func bindKeeperConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(KeeperConsumerABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_KeeperConsumer *KeeperConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _KeeperConsumer.Contract.KeeperConsumerCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_KeeperConsumer *KeeperConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _KeeperConsumer.Contract.KeeperConsumerTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_KeeperConsumer *KeeperConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _KeeperConsumer.Contract.KeeperConsumerTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_KeeperConsumer *KeeperConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _KeeperConsumer.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_KeeperConsumer *KeeperConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _KeeperConsumer.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_KeeperConsumer *KeeperConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _KeeperConsumer.Contract.contract.Transact(opts, method, params...) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes checkData) view returns(bool upkeepNeeded, bytes performData) -func (_KeeperConsumer *KeeperConsumerCaller) CheckUpkeep(opts *bind.CallOpts, checkData []byte) (struct { - UpkeepNeeded bool - PerformData []byte -}, error) { - var out []interface{} - err := _KeeperConsumer.contract.Call(opts, &out, "checkUpkeep", checkData) - - outstruct := new(struct { - UpkeepNeeded bool - PerformData []byte - }) - if err != nil { - return *outstruct, err - } - - outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) - - return *outstruct, err - -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes checkData) view returns(bool upkeepNeeded, bytes performData) -func (_KeeperConsumer *KeeperConsumerSession) CheckUpkeep(checkData []byte) (struct { - UpkeepNeeded bool - PerformData []byte -}, error) { - return _KeeperConsumer.Contract.CheckUpkeep(&_KeeperConsumer.CallOpts, checkData) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes checkData) view returns(bool upkeepNeeded, bytes performData) -func (_KeeperConsumer *KeeperConsumerCallerSession) CheckUpkeep(checkData []byte) (struct { - UpkeepNeeded bool - PerformData []byte -}, error) { - return _KeeperConsumer.Contract.CheckUpkeep(&_KeeperConsumer.CallOpts, checkData) -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _KeeperConsumer.contract.Call(opts, &out, "counter") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerSession) Counter() (*big.Int, error) { - return _KeeperConsumer.Contract.Counter(&_KeeperConsumer.CallOpts) -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCallerSession) Counter() (*big.Int, error) { - return _KeeperConsumer.Contract.Counter(&_KeeperConsumer.CallOpts) -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCaller) Interval(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _KeeperConsumer.contract.Call(opts, &out, "interval") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerSession) Interval() (*big.Int, error) { - return _KeeperConsumer.Contract.Interval(&_KeeperConsumer.CallOpts) -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCallerSession) Interval() (*big.Int, error) { - return _KeeperConsumer.Contract.Interval(&_KeeperConsumer.CallOpts) -} - -// LastTimeStamp is a free data retrieval call binding the contract method 0x3f3b3b27. -// -// Solidity: function lastTimeStamp() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCaller) LastTimeStamp(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _KeeperConsumer.contract.Call(opts, &out, "lastTimeStamp") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LastTimeStamp is a free data retrieval call binding the contract method 0x3f3b3b27. -// -// Solidity: function lastTimeStamp() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerSession) LastTimeStamp() (*big.Int, error) { - return _KeeperConsumer.Contract.LastTimeStamp(&_KeeperConsumer.CallOpts) -} - -// LastTimeStamp is a free data retrieval call binding the contract method 0x3f3b3b27. -// -// Solidity: function lastTimeStamp() view returns(uint256) -func (_KeeperConsumer *KeeperConsumerCallerSession) LastTimeStamp() (*big.Int, error) { - return _KeeperConsumer.Contract.LastTimeStamp(&_KeeperConsumer.CallOpts) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_KeeperConsumer *KeeperConsumerTransactor) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) { - return _KeeperConsumer.contract.Transact(opts, "performUpkeep", performData) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_KeeperConsumer *KeeperConsumerSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { - return _KeeperConsumer.Contract.PerformUpkeep(&_KeeperConsumer.TransactOpts, performData) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_KeeperConsumer *KeeperConsumerTransactorSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { - return _KeeperConsumer.Contract.PerformUpkeep(&_KeeperConsumer.TransactOpts, performData) -} diff --git a/integration-tests/contracts/ethereum/UpkeepCounter.go b/integration-tests/contracts/ethereum/UpkeepCounter.go deleted file mode 100644 index f0097bfb7b0..00000000000 --- a/integration-tests/contracts/ethereum/UpkeepCounter.go +++ /dev/null @@ -1,641 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethereum - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// UpkeepCounterMetaData contains all meta data concerning the UpkeepCounter contract. -var UpkeepCounterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"}],\"name\":\"setSpread\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b506040516104423803806104428339818101604052604081101561003357600080fd5b508051602090910151600091825560015560038190554360025560048190556005556103de806100646000396000f3fe608060405234801561001057600080fd5b506004361061008e5760003560e01c80632cb15864146100935780634585e33b146100ad57806361bc221a1461011d5780636250a13a146101255780636e04ff0d1461012d5780637f407edf1461021c578063806b984f1461023f578063917d895f14610247578063947a36fb1461024f578063d832d92f14610257575b600080fd5b61009b610273565b60408051918252519081900360200190f35b61011b600480360360208110156100c357600080fd5b810190602081018135600160201b8111156100dd57600080fd5b8201836020820111156100ef57600080fd5b803590602001918460018302840111600160201b8311171561011057600080fd5b509092509050610279565b005b61009b6102f0565b61009b6102f6565b61019b6004803603602081101561014357600080fd5b810190602081018135600160201b81111561015d57600080fd5b82018360208201111561016f57600080fd5b803590602001918460018302840111600160201b8311171561019057600080fd5b5090925090506102fc565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101e05781810151838201526020016101c8565b50505050905090810190601f16801561020d5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b61011b6004803603604081101561023257600080fd5b508035906020013561034e565b61009b610360565b61009b610366565b61009b61036c565b61025f610372565b604080519115158252519081900360200190f35b60045481565b60045461028557436004555b4360028190556005805460010190819055600454600354604080519283526020830194909452818401526060810191909152905132917f8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa919081900360800190a25050600254600355565b60055481565b60005481565b60006060610308610372565b848481818080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250959a92995091975050505050505050565b60009182556001556004819055600555565b60025481565b60035481565b60015481565b600060045460001415610387575060016103a5565b60005460045443031080156103a25750600154600254430310155b90505b9056fea264697066735822122040ec1d65fcf245bb817ffdc5ef880653b8cc880e41da1037b27143dcb90127c864736f6c63430007060033", -} - -// UpkeepCounterABI is the input ABI used to generate the binding from. -// Deprecated: Use UpkeepCounterMetaData.ABI instead. -var UpkeepCounterABI = UpkeepCounterMetaData.ABI - -// UpkeepCounterBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use UpkeepCounterMetaData.Bin instead. -var UpkeepCounterBin = UpkeepCounterMetaData.Bin - -// DeployUpkeepCounter deploys a new Ethereum contract, binding an instance of UpkeepCounter to it. -func DeployUpkeepCounter(auth *bind.TransactOpts, backend bind.ContractBackend, _testRange *big.Int, _interval *big.Int) (common.Address, *types.Transaction, *UpkeepCounter, error) { - parsed, err := UpkeepCounterMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(UpkeepCounterBin), backend, _testRange, _interval) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &UpkeepCounter{UpkeepCounterCaller: UpkeepCounterCaller{contract: contract}, UpkeepCounterTransactor: UpkeepCounterTransactor{contract: contract}, UpkeepCounterFilterer: UpkeepCounterFilterer{contract: contract}}, nil -} - -// UpkeepCounter is an auto generated Go binding around an Ethereum contract. -type UpkeepCounter struct { - UpkeepCounterCaller // Read-only binding to the contract - UpkeepCounterTransactor // Write-only binding to the contract - UpkeepCounterFilterer // Log filterer for contract events -} - -// UpkeepCounterCaller is an auto generated read-only Go binding around an Ethereum contract. -type UpkeepCounterCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepCounterTransactor is an auto generated write-only Go binding around an Ethereum contract. -type UpkeepCounterTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepCounterFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type UpkeepCounterFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepCounterSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type UpkeepCounterSession struct { - Contract *UpkeepCounter // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UpkeepCounterCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type UpkeepCounterCallerSession struct { - Contract *UpkeepCounterCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// UpkeepCounterTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type UpkeepCounterTransactorSession struct { - Contract *UpkeepCounterTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UpkeepCounterRaw is an auto generated low-level Go binding around an Ethereum contract. -type UpkeepCounterRaw struct { - Contract *UpkeepCounter // Generic contract binding to access the raw methods on -} - -// UpkeepCounterCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type UpkeepCounterCallerRaw struct { - Contract *UpkeepCounterCaller // Generic read-only contract binding to access the raw methods on -} - -// UpkeepCounterTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type UpkeepCounterTransactorRaw struct { - Contract *UpkeepCounterTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewUpkeepCounter creates a new instance of UpkeepCounter, bound to a specific deployed contract. -func NewUpkeepCounter(address common.Address, backend bind.ContractBackend) (*UpkeepCounter, error) { - contract, err := bindUpkeepCounter(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &UpkeepCounter{UpkeepCounterCaller: UpkeepCounterCaller{contract: contract}, UpkeepCounterTransactor: UpkeepCounterTransactor{contract: contract}, UpkeepCounterFilterer: UpkeepCounterFilterer{contract: contract}}, nil -} - -// NewUpkeepCounterCaller creates a new read-only instance of UpkeepCounter, bound to a specific deployed contract. -func NewUpkeepCounterCaller(address common.Address, caller bind.ContractCaller) (*UpkeepCounterCaller, error) { - contract, err := bindUpkeepCounter(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &UpkeepCounterCaller{contract: contract}, nil -} - -// NewUpkeepCounterTransactor creates a new write-only instance of UpkeepCounter, bound to a specific deployed contract. -func NewUpkeepCounterTransactor(address common.Address, transactor bind.ContractTransactor) (*UpkeepCounterTransactor, error) { - contract, err := bindUpkeepCounter(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &UpkeepCounterTransactor{contract: contract}, nil -} - -// NewUpkeepCounterFilterer creates a new log filterer instance of UpkeepCounter, bound to a specific deployed contract. -func NewUpkeepCounterFilterer(address common.Address, filterer bind.ContractFilterer) (*UpkeepCounterFilterer, error) { - contract, err := bindUpkeepCounter(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &UpkeepCounterFilterer{contract: contract}, nil -} - -// bindUpkeepCounter binds a generic wrapper to an already deployed contract. -func bindUpkeepCounter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(UpkeepCounterABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UpkeepCounter *UpkeepCounterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UpkeepCounter.Contract.UpkeepCounterCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UpkeepCounter *UpkeepCounterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UpkeepCounter.Contract.UpkeepCounterTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UpkeepCounter *UpkeepCounterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UpkeepCounter.Contract.UpkeepCounterTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UpkeepCounter *UpkeepCounterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UpkeepCounter.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UpkeepCounter *UpkeepCounterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UpkeepCounter.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UpkeepCounter *UpkeepCounterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UpkeepCounter.Contract.contract.Transact(opts, method, params...) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepCounter *UpkeepCounterCaller) CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "checkUpkeep", data) - - if err != nil { - return *new(bool), *new([]byte), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - out1 := *abi.ConvertType(out[1], new([]byte)).(*[]byte) - - return out0, out1, err - -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepCounter *UpkeepCounterSession) CheckUpkeep(data []byte) (bool, []byte, error) { - return _UpkeepCounter.Contract.CheckUpkeep(&_UpkeepCounter.CallOpts, data) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepCounter *UpkeepCounterCallerSession) CheckUpkeep(data []byte) (bool, []byte, error) { - return _UpkeepCounter.Contract.CheckUpkeep(&_UpkeepCounter.CallOpts, data) -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "counter") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) Counter() (*big.Int, error) { - return _UpkeepCounter.Contract.Counter(&_UpkeepCounter.CallOpts) -} - -// Counter is a free data retrieval call binding the contract method 0x61bc221a. -// -// Solidity: function counter() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) Counter() (*big.Int, error) { - return _UpkeepCounter.Contract.Counter(&_UpkeepCounter.CallOpts) -} - -// Eligible is a free data retrieval call binding the contract method 0xd832d92f. -// -// Solidity: function eligible() view returns(bool) -func (_UpkeepCounter *UpkeepCounterCaller) Eligible(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "eligible") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// Eligible is a free data retrieval call binding the contract method 0xd832d92f. -// -// Solidity: function eligible() view returns(bool) -func (_UpkeepCounter *UpkeepCounterSession) Eligible() (bool, error) { - return _UpkeepCounter.Contract.Eligible(&_UpkeepCounter.CallOpts) -} - -// Eligible is a free data retrieval call binding the contract method 0xd832d92f. -// -// Solidity: function eligible() view returns(bool) -func (_UpkeepCounter *UpkeepCounterCallerSession) Eligible() (bool, error) { - return _UpkeepCounter.Contract.Eligible(&_UpkeepCounter.CallOpts) -} - -// InitialBlock is a free data retrieval call binding the contract method 0x2cb15864. -// -// Solidity: function initialBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) InitialBlock(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "initialBlock") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// InitialBlock is a free data retrieval call binding the contract method 0x2cb15864. -// -// Solidity: function initialBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) InitialBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.InitialBlock(&_UpkeepCounter.CallOpts) -} - -// InitialBlock is a free data retrieval call binding the contract method 0x2cb15864. -// -// Solidity: function initialBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) InitialBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.InitialBlock(&_UpkeepCounter.CallOpts) -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) Interval(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "interval") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) Interval() (*big.Int, error) { - return _UpkeepCounter.Contract.Interval(&_UpkeepCounter.CallOpts) -} - -// Interval is a free data retrieval call binding the contract method 0x947a36fb. -// -// Solidity: function interval() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) Interval() (*big.Int, error) { - return _UpkeepCounter.Contract.Interval(&_UpkeepCounter.CallOpts) -} - -// LastBlock is a free data retrieval call binding the contract method 0x806b984f. -// -// Solidity: function lastBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) LastBlock(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "lastBlock") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LastBlock is a free data retrieval call binding the contract method 0x806b984f. -// -// Solidity: function lastBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) LastBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.LastBlock(&_UpkeepCounter.CallOpts) -} - -// LastBlock is a free data retrieval call binding the contract method 0x806b984f. -// -// Solidity: function lastBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) LastBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.LastBlock(&_UpkeepCounter.CallOpts) -} - -// PreviousPerformBlock is a free data retrieval call binding the contract method 0x917d895f. -// -// Solidity: function previousPerformBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) PreviousPerformBlock(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "previousPerformBlock") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// PreviousPerformBlock is a free data retrieval call binding the contract method 0x917d895f. -// -// Solidity: function previousPerformBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) PreviousPerformBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.PreviousPerformBlock(&_UpkeepCounter.CallOpts) -} - -// PreviousPerformBlock is a free data retrieval call binding the contract method 0x917d895f. -// -// Solidity: function previousPerformBlock() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) PreviousPerformBlock() (*big.Int, error) { - return _UpkeepCounter.Contract.PreviousPerformBlock(&_UpkeepCounter.CallOpts) -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCaller) TestRange(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepCounter.contract.Call(opts, &out, "testRange") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterSession) TestRange() (*big.Int, error) { - return _UpkeepCounter.Contract.TestRange(&_UpkeepCounter.CallOpts) -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepCounter *UpkeepCounterCallerSession) TestRange() (*big.Int, error) { - return _UpkeepCounter.Contract.TestRange(&_UpkeepCounter.CallOpts) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_UpkeepCounter *UpkeepCounterTransactor) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) { - return _UpkeepCounter.contract.Transact(opts, "performUpkeep", performData) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_UpkeepCounter *UpkeepCounterSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { - return _UpkeepCounter.Contract.PerformUpkeep(&_UpkeepCounter.TransactOpts, performData) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes performData) returns() -func (_UpkeepCounter *UpkeepCounterTransactorSession) PerformUpkeep(performData []byte) (*types.Transaction, error) { - return _UpkeepCounter.Contract.PerformUpkeep(&_UpkeepCounter.TransactOpts, performData) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _testRange, uint256 _interval) returns() -func (_UpkeepCounter *UpkeepCounterTransactor) SetSpread(opts *bind.TransactOpts, _testRange *big.Int, _interval *big.Int) (*types.Transaction, error) { - return _UpkeepCounter.contract.Transact(opts, "setSpread", _testRange, _interval) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _testRange, uint256 _interval) returns() -func (_UpkeepCounter *UpkeepCounterSession) SetSpread(_testRange *big.Int, _interval *big.Int) (*types.Transaction, error) { - return _UpkeepCounter.Contract.SetSpread(&_UpkeepCounter.TransactOpts, _testRange, _interval) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _testRange, uint256 _interval) returns() -func (_UpkeepCounter *UpkeepCounterTransactorSession) SetSpread(_testRange *big.Int, _interval *big.Int) (*types.Transaction, error) { - return _UpkeepCounter.Contract.SetSpread(&_UpkeepCounter.TransactOpts, _testRange, _interval) -} - -// UpkeepCounterPerformingUpkeepIterator is returned from FilterPerformingUpkeep and is used to iterate over the raw logs and unpacked data for PerformingUpkeep events raised by the UpkeepCounter contract. -type UpkeepCounterPerformingUpkeepIterator struct { - Event *UpkeepCounterPerformingUpkeep // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *UpkeepCounterPerformingUpkeepIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(UpkeepCounterPerformingUpkeep) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(UpkeepCounterPerformingUpkeep) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *UpkeepCounterPerformingUpkeepIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *UpkeepCounterPerformingUpkeepIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// UpkeepCounterPerformingUpkeep represents a PerformingUpkeep event raised by the UpkeepCounter contract. -type UpkeepCounterPerformingUpkeep struct { - From common.Address - InitialBlock *big.Int - LastBlock *big.Int - PreviousBlock *big.Int - Counter *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterPerformingUpkeep is a free log retrieval operation binding the contract event 0x8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa. -// -// Solidity: event PerformingUpkeep(address indexed from, uint256 initialBlock, uint256 lastBlock, uint256 previousBlock, uint256 counter) -func (_UpkeepCounter *UpkeepCounterFilterer) FilterPerformingUpkeep(opts *bind.FilterOpts, from []common.Address) (*UpkeepCounterPerformingUpkeepIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - - logs, sub, err := _UpkeepCounter.contract.FilterLogs(opts, "PerformingUpkeep", fromRule) - if err != nil { - return nil, err - } - return &UpkeepCounterPerformingUpkeepIterator{contract: _UpkeepCounter.contract, event: "PerformingUpkeep", logs: logs, sub: sub}, nil -} - -// WatchPerformingUpkeep is a free log subscription operation binding the contract event 0x8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa. -// -// Solidity: event PerformingUpkeep(address indexed from, uint256 initialBlock, uint256 lastBlock, uint256 previousBlock, uint256 counter) -func (_UpkeepCounter *UpkeepCounterFilterer) WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *UpkeepCounterPerformingUpkeep, from []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - - logs, sub, err := _UpkeepCounter.contract.WatchLogs(opts, "PerformingUpkeep", fromRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(UpkeepCounterPerformingUpkeep) - if err := _UpkeepCounter.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParsePerformingUpkeep is a log parse operation binding the contract event 0x8e8112f20a2134e18e591d2cdd68cd86a95d06e6328ede501fc6314f4a5075fa. -// -// Solidity: event PerformingUpkeep(address indexed from, uint256 initialBlock, uint256 lastBlock, uint256 previousBlock, uint256 counter) -func (_UpkeepCounter *UpkeepCounterFilterer) ParsePerformingUpkeep(log types.Log) (*UpkeepCounterPerformingUpkeep, error) { - event := new(UpkeepCounterPerformingUpkeep) - if err := _UpkeepCounter.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/integration-tests/contracts/ethereum/UpkeepPerformCounterRestrictive.go b/integration-tests/contracts/ethereum/UpkeepPerformCounterRestrictive.go deleted file mode 100644 index 092472fe99e..00000000000 --- a/integration-tests/contracts/ethereum/UpkeepPerformCounterRestrictive.go +++ /dev/null @@ -1,756 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethereum - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// UpkeepPerformCounterRestrictiveMetaData contains all meta data concerning the UpkeepPerformCounterRestrictive contract. -var UpkeepPerformCounterRestrictiveMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_testRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_averageEligibilityCadence\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"eligible\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialCall\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nextEligible\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"averageEligibilityCadence\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkEligible\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"checkUpkeep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCountPerforms\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialCall\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextEligible\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performGasToBurn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setCheckGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setPerformGasToBurn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_newTestRange\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_newAverageEligibilityCadence\",\"type\":\"uint256\"}],\"name\":\"setSpread\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testRange\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x6080604052600080556000600155600060075534801561001e57600080fd5b506040516105c93803806105c98339818101604052604081101561004157600080fd5b508051602090910151600291909155600355610567806100626000396000f3fe608060405234801561001057600080fd5b50600436106100c55760003560e01c806313bda75b146100ca5780632555d2cf146100e95780632ff3617d146101065780634585e33b14610120578063523d9b8a1461018e5780636250a13a146101965780636e04ff0d1461019e5780637145f11b1461028d5780637f407edf146102be578063926f086e146102e1578063a9a4c57c146102e9578063b30566b4146102f1578063c228a98e146102f9578063d826f88f14610301578063e303666f14610309575b600080fd5b6100e7600480360360208110156100e057600080fd5b5035610311565b005b6100e7600480360360208110156100ff57600080fd5b5035610316565b61010e61031b565b60408051918252519081900360200190f35b6100e76004803603602081101561013657600080fd5b810190602081018135600160201b81111561015057600080fd5b82018360208201111561016257600080fd5b803590602001918460018302840111600160201b8311171561018357600080fd5b509092509050610321565b61010e610404565b61010e61040a565b61020c600480360360208110156101b457600080fd5b810190602081018135600160201b8111156101ce57600080fd5b8201836020820111156101e057600080fd5b803590602001918460018302840111600160201b8311171561020157600080fd5b509092509050610410565b60405180831515815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610251578181015183820152602001610239565b50505050905090810190601f16801561027e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b6102aa600480360360208110156102a357600080fd5b503561048b565b604080519115158252519081900360200190f35b6100e7600480360360408110156102d457600080fd5b50803590602001356104a0565b61010e6104ab565b61010e6104b1565b61010e6104b7565b6102aa6104bd565b6100e76104cc565b61010e6104d6565b600455565b600555565b60045481565b60005a905060006103306104dc565b60005460015460408051841515815232602082015280820193909352606083019190915243608083018190529051929350917fbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc09181900360a00190a18161039657600080fd5b6000546103a35760008190555b6003546002026103b1610500565b816103b857fe5b06810160019081018155600780549091019055600019015b6005545a840310156103fd5780406000908152600660205260409020805460ff19169055600019016103d0565b5050505050565b60015481565b60025481565b6000606060005a9050600019430160005b6004545a840310156104585780801561044a5750814060009081526006602052604090205460ff165b600019909201919050610421565b6104606104dc565b6040805192151560208085019190915281518085039091018152928101905297909650945050505050565b60066020526000908152604090205460ff1681565b600291909155600355565b60005481565b60035481565b60055481565b60006104c76104dc565b905090565b6000808055600755565b60075490565b6000805415806104c7575060025460005443031080156104c7575050600154431190565b604080516000194301406020808301919091523082840152825180830384018152606090920190925280519101209056fea2646970667358221220a317dab4792a9ae36241f654e15b5fbb29c4a249e54654ea0b02219f739b347a64736f6c63430007060033", -} - -// UpkeepPerformCounterRestrictiveABI is the input ABI used to generate the binding from. -// Deprecated: Use UpkeepPerformCounterRestrictiveMetaData.ABI instead. -var UpkeepPerformCounterRestrictiveABI = UpkeepPerformCounterRestrictiveMetaData.ABI - -// UpkeepPerformCounterRestrictiveBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use UpkeepPerformCounterRestrictiveMetaData.Bin instead. -var UpkeepPerformCounterRestrictiveBin = UpkeepPerformCounterRestrictiveMetaData.Bin - -// DeployUpkeepPerformCounterRestrictive deploys a new Ethereum contract, binding an instance of UpkeepPerformCounterRestrictive to it. -func DeployUpkeepPerformCounterRestrictive(auth *bind.TransactOpts, backend bind.ContractBackend, _testRange *big.Int, _averageEligibilityCadence *big.Int) (common.Address, *types.Transaction, *UpkeepPerformCounterRestrictive, error) { - parsed, err := UpkeepPerformCounterRestrictiveMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(UpkeepPerformCounterRestrictiveBin), backend, _testRange, _averageEligibilityCadence) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &UpkeepPerformCounterRestrictive{UpkeepPerformCounterRestrictiveCaller: UpkeepPerformCounterRestrictiveCaller{contract: contract}, UpkeepPerformCounterRestrictiveTransactor: UpkeepPerformCounterRestrictiveTransactor{contract: contract}, UpkeepPerformCounterRestrictiveFilterer: UpkeepPerformCounterRestrictiveFilterer{contract: contract}}, nil -} - -// UpkeepPerformCounterRestrictive is an auto generated Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictive struct { - UpkeepPerformCounterRestrictiveCaller // Read-only binding to the contract - UpkeepPerformCounterRestrictiveTransactor // Write-only binding to the contract - UpkeepPerformCounterRestrictiveFilterer // Log filterer for contract events -} - -// UpkeepPerformCounterRestrictiveCaller is an auto generated read-only Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictiveCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepPerformCounterRestrictiveTransactor is an auto generated write-only Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictiveTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepPerformCounterRestrictiveFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type UpkeepPerformCounterRestrictiveFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UpkeepPerformCounterRestrictiveSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type UpkeepPerformCounterRestrictiveSession struct { - Contract *UpkeepPerformCounterRestrictive // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UpkeepPerformCounterRestrictiveCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type UpkeepPerformCounterRestrictiveCallerSession struct { - Contract *UpkeepPerformCounterRestrictiveCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// UpkeepPerformCounterRestrictiveTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type UpkeepPerformCounterRestrictiveTransactorSession struct { - Contract *UpkeepPerformCounterRestrictiveTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UpkeepPerformCounterRestrictiveRaw is an auto generated low-level Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictiveRaw struct { - Contract *UpkeepPerformCounterRestrictive // Generic contract binding to access the raw methods on -} - -// UpkeepPerformCounterRestrictiveCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictiveCallerRaw struct { - Contract *UpkeepPerformCounterRestrictiveCaller // Generic read-only contract binding to access the raw methods on -} - -// UpkeepPerformCounterRestrictiveTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type UpkeepPerformCounterRestrictiveTransactorRaw struct { - Contract *UpkeepPerformCounterRestrictiveTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewUpkeepPerformCounterRestrictive creates a new instance of UpkeepPerformCounterRestrictive, bound to a specific deployed contract. -func NewUpkeepPerformCounterRestrictive(address common.Address, backend bind.ContractBackend) (*UpkeepPerformCounterRestrictive, error) { - contract, err := bindUpkeepPerformCounterRestrictive(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &UpkeepPerformCounterRestrictive{UpkeepPerformCounterRestrictiveCaller: UpkeepPerformCounterRestrictiveCaller{contract: contract}, UpkeepPerformCounterRestrictiveTransactor: UpkeepPerformCounterRestrictiveTransactor{contract: contract}, UpkeepPerformCounterRestrictiveFilterer: UpkeepPerformCounterRestrictiveFilterer{contract: contract}}, nil -} - -// NewUpkeepPerformCounterRestrictiveCaller creates a new read-only instance of UpkeepPerformCounterRestrictive, bound to a specific deployed contract. -func NewUpkeepPerformCounterRestrictiveCaller(address common.Address, caller bind.ContractCaller) (*UpkeepPerformCounterRestrictiveCaller, error) { - contract, err := bindUpkeepPerformCounterRestrictive(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &UpkeepPerformCounterRestrictiveCaller{contract: contract}, nil -} - -// NewUpkeepPerformCounterRestrictiveTransactor creates a new write-only instance of UpkeepPerformCounterRestrictive, bound to a specific deployed contract. -func NewUpkeepPerformCounterRestrictiveTransactor(address common.Address, transactor bind.ContractTransactor) (*UpkeepPerformCounterRestrictiveTransactor, error) { - contract, err := bindUpkeepPerformCounterRestrictive(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &UpkeepPerformCounterRestrictiveTransactor{contract: contract}, nil -} - -// NewUpkeepPerformCounterRestrictiveFilterer creates a new log filterer instance of UpkeepPerformCounterRestrictive, bound to a specific deployed contract. -func NewUpkeepPerformCounterRestrictiveFilterer(address common.Address, filterer bind.ContractFilterer) (*UpkeepPerformCounterRestrictiveFilterer, error) { - contract, err := bindUpkeepPerformCounterRestrictive(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &UpkeepPerformCounterRestrictiveFilterer{contract: contract}, nil -} - -// bindUpkeepPerformCounterRestrictive binds a generic wrapper to an already deployed contract. -func bindUpkeepPerformCounterRestrictive(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(UpkeepPerformCounterRestrictiveABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UpkeepPerformCounterRestrictive.Contract.UpkeepPerformCounterRestrictiveCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.UpkeepPerformCounterRestrictiveTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.UpkeepPerformCounterRestrictiveTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UpkeepPerformCounterRestrictive.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.contract.Transact(opts, method, params...) -} - -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) AverageEligibilityCadence(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "averageEligibilityCadence") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) AverageEligibilityCadence() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.AverageEligibilityCadence(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// AverageEligibilityCadence is a free data retrieval call binding the contract method 0xa9a4c57c. -// -// Solidity: function averageEligibilityCadence() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) AverageEligibilityCadence() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.AverageEligibilityCadence(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) CheckEligible(opts *bind.CallOpts) (bool, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "checkEligible") - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) CheckEligible() (bool, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckEligible(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// CheckEligible is a free data retrieval call binding the contract method 0xc228a98e. -// -// Solidity: function checkEligible() view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) CheckEligible() (bool, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckEligible(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) CheckGasToBurn(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "checkGasToBurn") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) CheckGasToBurn() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckGasToBurn(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// CheckGasToBurn is a free data retrieval call binding the contract method 0x2ff3617d. -// -// Solidity: function checkGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) CheckGasToBurn() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckGasToBurn(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) CheckUpkeep(opts *bind.CallOpts, data []byte) (bool, []byte, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "checkUpkeep", data) - - if err != nil { - return *new(bool), *new([]byte), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - out1 := *abi.ConvertType(out[1], new([]byte)).(*[]byte) - - return out0, out1, err - -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) CheckUpkeep(data []byte) (bool, []byte, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckUpkeep(&_UpkeepPerformCounterRestrictive.CallOpts, data) -} - -// CheckUpkeep is a free data retrieval call binding the contract method 0x6e04ff0d. -// -// Solidity: function checkUpkeep(bytes data) view returns(bool, bytes) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) CheckUpkeep(data []byte) (bool, []byte, error) { - return _UpkeepPerformCounterRestrictive.Contract.CheckUpkeep(&_UpkeepPerformCounterRestrictive.CallOpts, data) -} - -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "dummyMap", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) DummyMap(arg0 [32]byte) (bool, error) { - return _UpkeepPerformCounterRestrictive.Contract.DummyMap(&_UpkeepPerformCounterRestrictive.CallOpts, arg0) -} - -// DummyMap is a free data retrieval call binding the contract method 0x7145f11b. -// -// Solidity: function dummyMap(bytes32 ) view returns(bool) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) DummyMap(arg0 [32]byte) (bool, error) { - return _UpkeepPerformCounterRestrictive.Contract.DummyMap(&_UpkeepPerformCounterRestrictive.CallOpts, arg0) -} - -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) GetCountPerforms(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "getCountPerforms") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) GetCountPerforms() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.GetCountPerforms(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// GetCountPerforms is a free data retrieval call binding the contract method 0xe303666f. -// -// Solidity: function getCountPerforms() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) GetCountPerforms() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.GetCountPerforms(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) InitialCall(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "initialCall") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) InitialCall() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.InitialCall(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// InitialCall is a free data retrieval call binding the contract method 0x926f086e. -// -// Solidity: function initialCall() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) InitialCall() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.InitialCall(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) NextEligible(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "nextEligible") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) NextEligible() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.NextEligible(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// NextEligible is a free data retrieval call binding the contract method 0x523d9b8a. -// -// Solidity: function nextEligible() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) NextEligible() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.NextEligible(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) PerformGasToBurn(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "performGasToBurn") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) PerformGasToBurn() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.PerformGasToBurn(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// PerformGasToBurn is a free data retrieval call binding the contract method 0xb30566b4. -// -// Solidity: function performGasToBurn() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) PerformGasToBurn() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.PerformGasToBurn(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCaller) TestRange(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _UpkeepPerformCounterRestrictive.contract.Call(opts, &out, "testRange") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) TestRange() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.TestRange(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// TestRange is a free data retrieval call binding the contract method 0x6250a13a. -// -// Solidity: function testRange() view returns(uint256) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveCallerSession) TestRange() (*big.Int, error) { - return _UpkeepPerformCounterRestrictive.Contract.TestRange(&_UpkeepPerformCounterRestrictive.CallOpts) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes ) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactor) PerformUpkeep(opts *bind.TransactOpts, arg0 []byte) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.contract.Transact(opts, "performUpkeep", arg0) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes ) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) PerformUpkeep(arg0 []byte) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.PerformUpkeep(&_UpkeepPerformCounterRestrictive.TransactOpts, arg0) -} - -// PerformUpkeep is a paid mutator transaction binding the contract method 0x4585e33b. -// -// Solidity: function performUpkeep(bytes ) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorSession) PerformUpkeep(arg0 []byte) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.PerformUpkeep(&_UpkeepPerformCounterRestrictive.TransactOpts, arg0) -} - -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.contract.Transact(opts, "reset") -} - -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) Reset() (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.Reset(&_UpkeepPerformCounterRestrictive.TransactOpts) -} - -// Reset is a paid mutator transaction binding the contract method 0xd826f88f. -// -// Solidity: function reset() returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorSession) Reset() (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.Reset(&_UpkeepPerformCounterRestrictive.TransactOpts) -} - -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactor) SetCheckGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.contract.Transact(opts, "setCheckGasToBurn", value) -} - -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) SetCheckGasToBurn(value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetCheckGasToBurn(&_UpkeepPerformCounterRestrictive.TransactOpts, value) -} - -// SetCheckGasToBurn is a paid mutator transaction binding the contract method 0x13bda75b. -// -// Solidity: function setCheckGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorSession) SetCheckGasToBurn(value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetCheckGasToBurn(&_UpkeepPerformCounterRestrictive.TransactOpts, value) -} - -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactor) SetPerformGasToBurn(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.contract.Transact(opts, "setPerformGasToBurn", value) -} - -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) SetPerformGasToBurn(value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetPerformGasToBurn(&_UpkeepPerformCounterRestrictive.TransactOpts, value) -} - -// SetPerformGasToBurn is a paid mutator transaction binding the contract method 0x2555d2cf. -// -// Solidity: function setPerformGasToBurn(uint256 value) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorSession) SetPerformGasToBurn(value *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetPerformGasToBurn(&_UpkeepPerformCounterRestrictive.TransactOpts, value) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactor) SetSpread(opts *bind.TransactOpts, _newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.contract.Transact(opts, "setSpread", _newTestRange, _newAverageEligibilityCadence) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveSession) SetSpread(_newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetSpread(&_UpkeepPerformCounterRestrictive.TransactOpts, _newTestRange, _newAverageEligibilityCadence) -} - -// SetSpread is a paid mutator transaction binding the contract method 0x7f407edf. -// -// Solidity: function setSpread(uint256 _newTestRange, uint256 _newAverageEligibilityCadence) returns() -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveTransactorSession) SetSpread(_newTestRange *big.Int, _newAverageEligibilityCadence *big.Int) (*types.Transaction, error) { - return _UpkeepPerformCounterRestrictive.Contract.SetSpread(&_UpkeepPerformCounterRestrictive.TransactOpts, _newTestRange, _newAverageEligibilityCadence) -} - -// UpkeepPerformCounterRestrictivePerformingUpkeepIterator is returned from FilterPerformingUpkeep and is used to iterate over the raw logs and unpacked data for PerformingUpkeep events raised by the UpkeepPerformCounterRestrictive contract. -type UpkeepPerformCounterRestrictivePerformingUpkeepIterator struct { - Event *UpkeepPerformCounterRestrictivePerformingUpkeep // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *UpkeepPerformCounterRestrictivePerformingUpkeepIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(UpkeepPerformCounterRestrictivePerformingUpkeep) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(UpkeepPerformCounterRestrictivePerformingUpkeep) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *UpkeepPerformCounterRestrictivePerformingUpkeepIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *UpkeepPerformCounterRestrictivePerformingUpkeepIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// UpkeepPerformCounterRestrictivePerformingUpkeep represents a PerformingUpkeep event raised by the UpkeepPerformCounterRestrictive contract. -type UpkeepPerformCounterRestrictivePerformingUpkeep struct { - Eligible bool - From common.Address - InitialCall *big.Int - NextEligible *big.Int - BlockNumber *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterPerformingUpkeep is a free log retrieval operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveFilterer) FilterPerformingUpkeep(opts *bind.FilterOpts) (*UpkeepPerformCounterRestrictivePerformingUpkeepIterator, error) { - - logs, sub, err := _UpkeepPerformCounterRestrictive.contract.FilterLogs(opts, "PerformingUpkeep") - if err != nil { - return nil, err - } - return &UpkeepPerformCounterRestrictivePerformingUpkeepIterator{contract: _UpkeepPerformCounterRestrictive.contract, event: "PerformingUpkeep", logs: logs, sub: sub}, nil -} - -// WatchPerformingUpkeep is a free log subscription operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveFilterer) WatchPerformingUpkeep(opts *bind.WatchOpts, sink chan<- *UpkeepPerformCounterRestrictivePerformingUpkeep) (event.Subscription, error) { - - logs, sub, err := _UpkeepPerformCounterRestrictive.contract.WatchLogs(opts, "PerformingUpkeep") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(UpkeepPerformCounterRestrictivePerformingUpkeep) - if err := _UpkeepPerformCounterRestrictive.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParsePerformingUpkeep is a log parse operation binding the contract event 0xbd6b6608a51477954e8b498c633bda87e5cd555e06ead50486398d9e3b9cebc0. -// -// Solidity: event PerformingUpkeep(bool eligible, address from, uint256 initialCall, uint256 nextEligible, uint256 blockNumber) -func (_UpkeepPerformCounterRestrictive *UpkeepPerformCounterRestrictiveFilterer) ParsePerformingUpkeep(log types.Log) (*UpkeepPerformCounterRestrictivePerformingUpkeep, error) { - event := new(UpkeepPerformCounterRestrictivePerformingUpkeep) - if err := _UpkeepPerformCounterRestrictive.contract.UnpackLog(event, "PerformingUpkeep", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/integration-tests/contracts/ethereum/VRFv2Consumer.go b/integration-tests/contracts/ethereum/VRFv2Consumer.go deleted file mode 100644 index 9793d96a11f..00000000000 --- a/integration-tests/contracts/ethereum/VRFv2Consumer.go +++ /dev/null @@ -1,1045 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package ethereum - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// VRFv2ConsumerMetaData contains all meta data concerning the VRFv2Consumer contract. -var VRFv2ConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"RequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"RequestSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"}],\"name\":\"rawFulfillRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"requestIds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"exists\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620018a4380380620018a483398181016040528101906200003791906200034e565b33806000838073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603620000e3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620000da90620003e1565b60405180910390fd5b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146200016a576200016981620001b560201b60201c565b5b50505080600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505062000475565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000226576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200021d9062000453565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127860405160405180910390a350565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200031682620002e9565b9050919050565b620003288162000309565b81146200033457600080fd5b50565b60008151905062000348816200031d565b92915050565b600060208284031215620003675762000366620002e4565b5b6000620003778482850162000337565b91505092915050565b600082825260208201905092915050565b7f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000600082015250565b6000620003c960188362000380565b9150620003d68262000391565b602082019050919050565b60006020820190508181036000830152620003fc81620003ba565b9050919050565b7f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000600082015250565b60006200043b60178362000380565b9150620004488262000403565b602082019050919050565b600060208201905081810360008301526200046e816200042c565b9050919050565b60805161140c62000498600039600081816101da015261022e015261140c6000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80639561f023116100665780639561f0231461010c578063a168fa891461013c578063d8a4676f1461016d578063f2fde38b1461019e578063fc2a88c3146101ba57610093565b80631fe543e31461009857806379ba5097146100b45780638796ba8c146100be5780638da5cb5b146100ee575b600080fd5b6100b260048036038101906100ad9190610cc1565b6101d8565b005b6100bc610298565b005b6100d860048036038101906100d39190610d1d565b61042d565b6040516100e59190610d59565b60405180910390f35b6100f6610451565b6040516101039190610db5565b60405180910390f35b61012660048036038101906101219190610ebc565b61047a565b6040516101339190610d59565b60405180910390f35b61015660048036038101906101519190610d1d565b61067b565b604051610164929190610f52565b60405180910390f35b61018760048036038101906101829190610d1d565b6106b9565b604051610195929190611039565b60405180910390f35b6101b860048036038101906101b39190611095565b6107e4565b005b6101c26107f8565b6040516101cf9190610d59565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461028a57337f00000000000000000000000000000000000000000000000000000000000000006040517f1cf993f40000000000000000000000000000000000000000000000000000000081526004016102819291906110c2565b60405180910390fd5b61029482826107fe565b5050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610328576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031f90611148565b60405180910390fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350565b6004818154811061043d57600080fd5b906000526020600020016000915090505481565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006104846108f8565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635d3b1d3083888789886040518663ffffffff1660e01b81526004016104e79594939291906111a4565b6020604051808303816000875af1158015610506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052a919061120c565b90506040518060600160405280600015158152602001600115158152602001600067ffffffffffffffff81111561056457610563610b7e565b5b6040519080825280602002602001820160405280156105925781602001602082028036833780820191505090505b508152506002600083815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff0219169083151502179055506040820151816001019080519060200190610605929190610ab4565b509050506004819080600181540180825580915050600190039060005260206000200160009091909190915055806005819055507fcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee818460405161066a929190611239565b60405180910390a195945050505050565b60026020528060005260406000206000915090508060000160009054906101000a900460ff16908060000160019054906101000a900460ff16905082565b600060606002600084815260200190815260200160002060000160019054906101000a900460ff16610720576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610717906112ae565b60405180910390fd5b6000600260008581526020019081526020016000206040518060600160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff16151515158152602001600182018054806020026020016040519081016040528092919081815260200182805480156107c557602002820191906000526020600020905b8154815260200190600101908083116107b1575b5050505050815250509050806000015181604001519250925050915091565b6107ec6108f8565b6107f581610988565b50565b60055481565b6002600083815260200190815260200160002060000160019054906101000a900460ff16610861576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610858906112ae565b60405180910390fd5b60016002600084815260200190815260200160002060000160006101000a81548160ff021916908315150217905550806002600084815260200190815260200160002060010190805190602001906108ba929190610ab4565b507ffe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d82826040516108ec9291906112ce565b60405180910390a15050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610986576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097d9061134a565b60405180910390fd5b565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036109f6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ed906113b6565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127860405160405180910390a350565b828054828255906000526020600020908101928215610af0579160200282015b82811115610aef578251825591602001919060010190610ad4565b5b509050610afd9190610b01565b5090565b5b80821115610b1a576000816000905550600101610b02565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610b4581610b32565b8114610b5057600080fd5b50565b600081359050610b6281610b3c565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610bb682610b6d565b810181811067ffffffffffffffff82111715610bd557610bd4610b7e565b5b80604052505050565b6000610be8610b1e565b9050610bf48282610bad565b919050565b600067ffffffffffffffff821115610c1457610c13610b7e565b5b602082029050602081019050919050565b600080fd5b6000610c3d610c3884610bf9565b610bde565b90508083825260208201905060208402830185811115610c6057610c5f610c25565b5b835b81811015610c895780610c758882610b53565b845260208401935050602081019050610c62565b5050509392505050565b600082601f830112610ca857610ca7610b68565b5b8135610cb8848260208601610c2a565b91505092915050565b60008060408385031215610cd857610cd7610b28565b5b6000610ce685828601610b53565b925050602083013567ffffffffffffffff811115610d0757610d06610b2d565b5b610d1385828601610c93565b9150509250929050565b600060208284031215610d3357610d32610b28565b5b6000610d4184828501610b53565b91505092915050565b610d5381610b32565b82525050565b6000602082019050610d6e6000830184610d4a565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610d9f82610d74565b9050919050565b610daf81610d94565b82525050565b6000602082019050610dca6000830184610da6565b92915050565b600067ffffffffffffffff82169050919050565b610ded81610dd0565b8114610df857600080fd5b50565b600081359050610e0a81610de4565b92915050565b600063ffffffff82169050919050565b610e2981610e10565b8114610e3457600080fd5b50565b600081359050610e4681610e20565b92915050565b600061ffff82169050919050565b610e6381610e4c565b8114610e6e57600080fd5b50565b600081359050610e8081610e5a565b92915050565b6000819050919050565b610e9981610e86565b8114610ea457600080fd5b50565b600081359050610eb681610e90565b92915050565b600080600080600060a08688031215610ed857610ed7610b28565b5b6000610ee688828901610dfb565b9550506020610ef788828901610e37565b9450506040610f0888828901610e71565b9350506060610f1988828901610e37565b9250506080610f2a88828901610ea7565b9150509295509295909350565b60008115159050919050565b610f4c81610f37565b82525050565b6000604082019050610f676000830185610f43565b610f746020830184610f43565b9392505050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b610fb081610b32565b82525050565b6000610fc28383610fa7565b60208301905092915050565b6000602082019050919050565b6000610fe682610f7b565b610ff08185610f86565b9350610ffb83610f97565b8060005b8381101561102c5781516110138882610fb6565b975061101e83610fce565b925050600181019050610fff565b5085935050505092915050565b600060408201905061104e6000830185610f43565b81810360208301526110608184610fdb565b90509392505050565b61107281610d94565b811461107d57600080fd5b50565b60008135905061108f81611069565b92915050565b6000602082840312156110ab576110aa610b28565b5b60006110b984828501611080565b91505092915050565b60006040820190506110d76000830185610da6565b6110e46020830184610da6565b9392505050565b600082825260208201905092915050565b7f4d7573742062652070726f706f736564206f776e657200000000000000000000600082015250565b60006111326016836110eb565b915061113d826110fc565b602082019050919050565b6000602082019050818103600083015261116181611125565b9050919050565b61117181610e86565b82525050565b61118081610dd0565b82525050565b61118f81610e4c565b82525050565b61119e81610e10565b82525050565b600060a0820190506111b96000830188611168565b6111c66020830187611177565b6111d36040830186611186565b6111e06060830185611195565b6111ed6080830184611195565b9695505050505050565b60008151905061120681610b3c565b92915050565b60006020828403121561122257611221610b28565b5b6000611230848285016111f7565b91505092915050565b600060408201905061124e6000830185610d4a565b61125b6020830184611195565b9392505050565b7f72657175657374206e6f7420666f756e64000000000000000000000000000000600082015250565b60006112986011836110eb565b91506112a382611262565b602082019050919050565b600060208201905081810360008301526112c78161128b565b9050919050565b60006040820190506112e36000830185610d4a565b81810360208301526112f58184610fdb565b90509392505050565b7f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000600082015250565b60006113346016836110eb565b915061133f826112fe565b602082019050919050565b6000602082019050818103600083015261136381611327565b9050919050565b7f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000600082015250565b60006113a06017836110eb565b91506113ab8261136a565b602082019050919050565b600060208201905081810360008301526113cf81611393565b905091905056fea2646970667358221220e3ffc5c5c5c9efece6a6dd560edba3d094c9853bc2c4400e1d3ea7e3d950ecfa64736f6c63430008110033", -} - -// VRFv2ConsumerABI is the input ABI used to generate the binding from. -// Deprecated: Use VRFv2ConsumerMetaData.ABI instead. -var VRFv2ConsumerABI = VRFv2ConsumerMetaData.ABI - -// VRFv2ConsumerBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use VRFv2ConsumerMetaData.Bin instead. -var VRFv2ConsumerBin = VRFv2ConsumerMetaData.Bin - -// DeployVRFv2Consumer deploys a new Ethereum contract, binding an instance of VRFv2Consumer to it. -func DeployVRFv2Consumer(auth *bind.TransactOpts, backend bind.ContractBackend, vrfCoordinator common.Address) (common.Address, *types.Transaction, *VRFv2Consumer, error) { - parsed, err := VRFv2ConsumerMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFv2ConsumerBin), backend, vrfCoordinator) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &VRFv2Consumer{VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil -} - -// VRFv2Consumer is an auto generated Go binding around an Ethereum contract. -type VRFv2Consumer struct { - VRFv2ConsumerCaller // Read-only binding to the contract - VRFv2ConsumerTransactor // Write-only binding to the contract - VRFv2ConsumerFilterer // Log filterer for contract events -} - -// VRFv2ConsumerCaller is an auto generated read-only Go binding around an Ethereum contract. -type VRFv2ConsumerCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// VRFv2ConsumerTransactor is an auto generated write-only Go binding around an Ethereum contract. -type VRFv2ConsumerTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// VRFv2ConsumerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type VRFv2ConsumerFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// VRFv2ConsumerSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type VRFv2ConsumerSession struct { - Contract *VRFv2Consumer // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// VRFv2ConsumerCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type VRFv2ConsumerCallerSession struct { - Contract *VRFv2ConsumerCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// VRFv2ConsumerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type VRFv2ConsumerTransactorSession struct { - Contract *VRFv2ConsumerTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// VRFv2ConsumerRaw is an auto generated low-level Go binding around an Ethereum contract. -type VRFv2ConsumerRaw struct { - Contract *VRFv2Consumer // Generic contract binding to access the raw methods on -} - -// VRFv2ConsumerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type VRFv2ConsumerCallerRaw struct { - Contract *VRFv2ConsumerCaller // Generic read-only contract binding to access the raw methods on -} - -// VRFv2ConsumerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type VRFv2ConsumerTransactorRaw struct { - Contract *VRFv2ConsumerTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewVRFv2Consumer creates a new instance of VRFv2Consumer, bound to a specific deployed contract. -func NewVRFv2Consumer(address common.Address, backend bind.ContractBackend) (*VRFv2Consumer, error) { - contract, err := bindVRFv2Consumer(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &VRFv2Consumer{VRFv2ConsumerCaller: VRFv2ConsumerCaller{contract: contract}, VRFv2ConsumerTransactor: VRFv2ConsumerTransactor{contract: contract}, VRFv2ConsumerFilterer: VRFv2ConsumerFilterer{contract: contract}}, nil -} - -// NewVRFv2ConsumerCaller creates a new read-only instance of VRFv2Consumer, bound to a specific deployed contract. -func NewVRFv2ConsumerCaller(address common.Address, caller bind.ContractCaller) (*VRFv2ConsumerCaller, error) { - contract, err := bindVRFv2Consumer(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &VRFv2ConsumerCaller{contract: contract}, nil -} - -// NewVRFv2ConsumerTransactor creates a new write-only instance of VRFv2Consumer, bound to a specific deployed contract. -func NewVRFv2ConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFv2ConsumerTransactor, error) { - contract, err := bindVRFv2Consumer(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &VRFv2ConsumerTransactor{contract: contract}, nil -} - -// NewVRFv2ConsumerFilterer creates a new log filterer instance of VRFv2Consumer, bound to a specific deployed contract. -func NewVRFv2ConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFv2ConsumerFilterer, error) { - contract, err := bindVRFv2Consumer(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &VRFv2ConsumerFilterer{contract: contract}, nil -} - -// bindVRFv2Consumer binds a generic wrapper to an already deployed contract. -func bindVRFv2Consumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(VRFv2ConsumerABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_VRFv2Consumer *VRFv2ConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFv2Consumer.Contract.VRFv2ConsumerCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_VRFv2Consumer *VRFv2ConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.VRFv2ConsumerTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_VRFv2Consumer *VRFv2ConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.VRFv2ConsumerTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_VRFv2Consumer *VRFv2ConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _VRFv2Consumer.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_VRFv2Consumer *VRFv2ConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_VRFv2Consumer *VRFv2ConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.contract.Transact(opts, method, params...) -} - -// GetRequestStatus is a free data retrieval call binding the contract method 0xd8a4676f. -// -// Solidity: function getRequestStatus(uint256 _requestId) view returns(bool fulfilled, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (struct { - Fulfilled bool - RandomWords []*big.Int -}, error) { - var out []interface{} - err := _VRFv2Consumer.contract.Call(opts, &out, "getRequestStatus", _requestId) - - outstruct := new(struct { - Fulfilled bool - RandomWords []*big.Int - }) - if err != nil { - return *outstruct, err - } - - outstruct.Fulfilled = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.RandomWords = *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int) - - return *outstruct, err - -} - -// GetRequestStatus is a free data retrieval call binding the contract method 0xd8a4676f. -// -// Solidity: function getRequestStatus(uint256 _requestId) view returns(bool fulfilled, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerSession) GetRequestStatus(_requestId *big.Int) (struct { - Fulfilled bool - RandomWords []*big.Int -}, error) { - return _VRFv2Consumer.Contract.GetRequestStatus(&_VRFv2Consumer.CallOpts, _requestId) -} - -// GetRequestStatus is a free data retrieval call binding the contract method 0xd8a4676f. -// -// Solidity: function getRequestStatus(uint256 _requestId) view returns(bool fulfilled, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerCallerSession) GetRequestStatus(_requestId *big.Int) (struct { - Fulfilled bool - RandomWords []*big.Int -}, error) { - return _VRFv2Consumer.Contract.GetRequestStatus(&_VRFv2Consumer.CallOpts, _requestId) -} - -// LastRequestId is a free data retrieval call binding the contract method 0xfc2a88c3. -// -// Solidity: function lastRequestId() view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerCaller) LastRequestId(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _VRFv2Consumer.contract.Call(opts, &out, "lastRequestId") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LastRequestId is a free data retrieval call binding the contract method 0xfc2a88c3. -// -// Solidity: function lastRequestId() view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerSession) LastRequestId() (*big.Int, error) { - return _VRFv2Consumer.Contract.LastRequestId(&_VRFv2Consumer.CallOpts) -} - -// LastRequestId is a free data retrieval call binding the contract method 0xfc2a88c3. -// -// Solidity: function lastRequestId() view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerCallerSession) LastRequestId() (*big.Int, error) { - return _VRFv2Consumer.Contract.LastRequestId(&_VRFv2Consumer.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_VRFv2Consumer *VRFv2ConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFv2Consumer.contract.Call(opts, &out, "owner") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_VRFv2Consumer *VRFv2ConsumerSession) Owner() (common.Address, error) { - return _VRFv2Consumer.Contract.Owner(&_VRFv2Consumer.CallOpts) -} - -// Owner is a free data retrieval call binding the contract method 0x8da5cb5b. -// -// Solidity: function owner() view returns(address) -func (_VRFv2Consumer *VRFv2ConsumerCallerSession) Owner() (common.Address, error) { - return _VRFv2Consumer.Contract.Owner(&_VRFv2Consumer.CallOpts) -} - -// RequestIds is a free data retrieval call binding the contract method 0x8796ba8c. -// -// Solidity: function requestIds(uint256 ) view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerCaller) RequestIds(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { - var out []interface{} - err := _VRFv2Consumer.contract.Call(opts, &out, "requestIds", arg0) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// RequestIds is a free data retrieval call binding the contract method 0x8796ba8c. -// -// Solidity: function requestIds(uint256 ) view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerSession) RequestIds(arg0 *big.Int) (*big.Int, error) { - return _VRFv2Consumer.Contract.RequestIds(&_VRFv2Consumer.CallOpts, arg0) -} - -// RequestIds is a free data retrieval call binding the contract method 0x8796ba8c. -// -// Solidity: function requestIds(uint256 ) view returns(uint256) -func (_VRFv2Consumer *VRFv2ConsumerCallerSession) RequestIds(arg0 *big.Int) (*big.Int, error) { - return _VRFv2Consumer.Contract.RequestIds(&_VRFv2Consumer.CallOpts, arg0) -} - -// SRequests is a free data retrieval call binding the contract method 0xa168fa89. -// -// Solidity: function s_requests(uint256 ) view returns(bool fulfilled, bool exists) -func (_VRFv2Consumer *VRFv2ConsumerCaller) SRequests(opts *bind.CallOpts, arg0 *big.Int) (struct { - Fulfilled bool - Exists bool -}, error) { - var out []interface{} - err := _VRFv2Consumer.contract.Call(opts, &out, "s_requests", arg0) - - outstruct := new(struct { - Fulfilled bool - Exists bool - }) - if err != nil { - return *outstruct, err - } - - outstruct.Fulfilled = *abi.ConvertType(out[0], new(bool)).(*bool) - outstruct.Exists = *abi.ConvertType(out[1], new(bool)).(*bool) - - return *outstruct, err - -} - -// SRequests is a free data retrieval call binding the contract method 0xa168fa89. -// -// Solidity: function s_requests(uint256 ) view returns(bool fulfilled, bool exists) -func (_VRFv2Consumer *VRFv2ConsumerSession) SRequests(arg0 *big.Int) (struct { - Fulfilled bool - Exists bool -}, error) { - return _VRFv2Consumer.Contract.SRequests(&_VRFv2Consumer.CallOpts, arg0) -} - -// SRequests is a free data retrieval call binding the contract method 0xa168fa89. -// -// Solidity: function s_requests(uint256 ) view returns(bool fulfilled, bool exists) -func (_VRFv2Consumer *VRFv2ConsumerCallerSession) SRequests(arg0 *big.Int) (struct { - Fulfilled bool - Exists bool -}, error) { - return _VRFv2Consumer.Contract.SRequests(&_VRFv2Consumer.CallOpts, arg0) -} - -// AcceptOwnership is a paid mutator transaction binding the contract method 0x79ba5097. -// -// Solidity: function acceptOwnership() returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFv2Consumer.contract.Transact(opts, "acceptOwnership") -} - -// AcceptOwnership is a paid mutator transaction binding the contract method 0x79ba5097. -// -// Solidity: function acceptOwnership() returns() -func (_VRFv2Consumer *VRFv2ConsumerSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFv2Consumer.Contract.AcceptOwnership(&_VRFv2Consumer.TransactOpts) -} - -// AcceptOwnership is a paid mutator transaction binding the contract method 0x79ba5097. -// -// Solidity: function acceptOwnership() returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFv2Consumer.Contract.AcceptOwnership(&_VRFv2Consumer.TransactOpts) -} - -// RawFulfillRandomWords is a paid mutator transaction binding the contract method 0x1fe543e3. -// -// Solidity: function rawFulfillRandomWords(uint256 requestId, uint256[] randomWords) returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { - return _VRFv2Consumer.contract.Transact(opts, "rawFulfillRandomWords", requestId, randomWords) -} - -// RawFulfillRandomWords is a paid mutator transaction binding the contract method 0x1fe543e3. -// -// Solidity: function rawFulfillRandomWords(uint256 requestId, uint256[] randomWords) returns() -func (_VRFv2Consumer *VRFv2ConsumerSession) RawFulfillRandomWords(requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.RawFulfillRandomWords(&_VRFv2Consumer.TransactOpts, requestId, randomWords) -} - -// RawFulfillRandomWords is a paid mutator transaction binding the contract method 0x1fe543e3. -// -// Solidity: function rawFulfillRandomWords(uint256 requestId, uint256[] randomWords) returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) RawFulfillRandomWords(requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.RawFulfillRandomWords(&_VRFv2Consumer.TransactOpts, requestId, randomWords) -} - -// RequestRandomWords is a paid mutator transaction binding the contract method 0x9561f023. -// -// Solidity: function requestRandomWords(uint64 subId, uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, bytes32 keyHash) returns(uint256 requestId) -func (_VRFv2Consumer *VRFv2ConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { - return _VRFv2Consumer.contract.Transact(opts, "requestRandomWords", subId, callbackGasLimit, requestConfirmations, numWords, keyHash) -} - -// RequestRandomWords is a paid mutator transaction binding the contract method 0x9561f023. -// -// Solidity: function requestRandomWords(uint64 subId, uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, bytes32 keyHash) returns(uint256 requestId) -func (_VRFv2Consumer *VRFv2ConsumerSession) RequestRandomWords(subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.RequestRandomWords(&_VRFv2Consumer.TransactOpts, subId, callbackGasLimit, requestConfirmations, numWords, keyHash) -} - -// RequestRandomWords is a paid mutator transaction binding the contract method 0x9561f023. -// -// Solidity: function requestRandomWords(uint64 subId, uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, bytes32 keyHash) returns(uint256 requestId) -func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) RequestRandomWords(subId uint64, callbackGasLimit uint32, requestConfirmations uint16, numWords uint32, keyHash [32]byte) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.RequestRandomWords(&_VRFv2Consumer.TransactOpts, subId, callbackGasLimit, requestConfirmations, numWords, keyHash) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address to) returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _VRFv2Consumer.contract.Transact(opts, "transferOwnership", to) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address to) returns() -func (_VRFv2Consumer *VRFv2ConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.TransferOwnership(&_VRFv2Consumer.TransactOpts, to) -} - -// TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. -// -// Solidity: function transferOwnership(address to) returns() -func (_VRFv2Consumer *VRFv2ConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFv2Consumer.Contract.TransferOwnership(&_VRFv2Consumer.TransactOpts, to) -} - -// VRFv2ConsumerOwnershipTransferRequestedIterator is returned from FilterOwnershipTransferRequested and is used to iterate over the raw logs and unpacked data for OwnershipTransferRequested events raised by the VRFv2Consumer contract. -type VRFv2ConsumerOwnershipTransferRequestedIterator struct { - Event *VRFv2ConsumerOwnershipTransferRequested // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerOwnershipTransferRequested) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerOwnershipTransferRequested) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *VRFv2ConsumerOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// VRFv2ConsumerOwnershipTransferRequested represents a OwnershipTransferRequested event raised by the VRFv2Consumer contract. -type VRFv2ConsumerOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferRequested is a free log retrieval operation binding the contract event 0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278. -// -// Solidity: event OwnershipTransferRequested(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferRequestedIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFv2ConsumerOwnershipTransferRequestedIterator{contract: _VRFv2Consumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferRequested is a free log subscription operation binding the contract event 0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278. -// -// Solidity: event OwnershipTransferRequested(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(VRFv2ConsumerOwnershipTransferRequested) - if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOwnershipTransferRequested is a log parse operation binding the contract event 0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278. -// -// Solidity: event OwnershipTransferRequested(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFv2ConsumerOwnershipTransferRequested, error) { - event := new(VRFv2ConsumerOwnershipTransferRequested) - if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// VRFv2ConsumerOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the VRFv2Consumer contract. -type VRFv2ConsumerOwnershipTransferredIterator struct { - Event *VRFv2ConsumerOwnershipTransferred // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *VRFv2ConsumerOwnershipTransferredIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerOwnershipTransferred) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *VRFv2ConsumerOwnershipTransferredIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *VRFv2ConsumerOwnershipTransferredIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// VRFv2ConsumerOwnershipTransferred represents a OwnershipTransferred event raised by the VRFv2Consumer contract. -type VRFv2ConsumerOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFv2ConsumerOwnershipTransferredIterator, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFv2ConsumerOwnershipTransferredIterator{contract: _VRFv2Consumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil -} - -// WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - - var fromRule []interface{} - for _, fromItem := range from { - fromRule = append(fromRule, fromItem) - } - var toRule []interface{} - for _, toItem := range to { - toRule = append(toRule, toItem) - } - - logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(VRFv2ConsumerOwnershipTransferred) - if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. -// -// Solidity: event OwnershipTransferred(address indexed from, address indexed to) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*VRFv2ConsumerOwnershipTransferred, error) { - event := new(VRFv2ConsumerOwnershipTransferred) - if err := _VRFv2Consumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// VRFv2ConsumerRequestFulfilledIterator is returned from FilterRequestFulfilled and is used to iterate over the raw logs and unpacked data for RequestFulfilled events raised by the VRFv2Consumer contract. -type VRFv2ConsumerRequestFulfilledIterator struct { - Event *VRFv2ConsumerRequestFulfilled // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *VRFv2ConsumerRequestFulfilledIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerRequestFulfilled) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerRequestFulfilled) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *VRFv2ConsumerRequestFulfilledIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *VRFv2ConsumerRequestFulfilledIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// VRFv2ConsumerRequestFulfilled represents a RequestFulfilled event raised by the VRFv2Consumer contract. -type VRFv2ConsumerRequestFulfilled struct { - RequestId *big.Int - RandomWords []*big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRequestFulfilled is a free log retrieval operation binding the contract event 0xfe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d. -// -// Solidity: event RequestFulfilled(uint256 requestId, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterRequestFulfilled(opts *bind.FilterOpts) (*VRFv2ConsumerRequestFulfilledIterator, error) { - - logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "RequestFulfilled") - if err != nil { - return nil, err - } - return &VRFv2ConsumerRequestFulfilledIterator{contract: _VRFv2Consumer.contract, event: "RequestFulfilled", logs: logs, sub: sub}, nil -} - -// WatchRequestFulfilled is a free log subscription operation binding the contract event 0xfe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d. -// -// Solidity: event RequestFulfilled(uint256 requestId, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestFulfilled) (event.Subscription, error) { - - logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "RequestFulfilled") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(VRFv2ConsumerRequestFulfilled) - if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestFulfilled", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRequestFulfilled is a log parse operation binding the contract event 0xfe2e2d779dba245964d4e3ef9b994be63856fd568bf7d3ca9e224755cb1bd54d. -// -// Solidity: event RequestFulfilled(uint256 requestId, uint256[] randomWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseRequestFulfilled(log types.Log) (*VRFv2ConsumerRequestFulfilled, error) { - event := new(VRFv2ConsumerRequestFulfilled) - if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestFulfilled", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// VRFv2ConsumerRequestSentIterator is returned from FilterRequestSent and is used to iterate over the raw logs and unpacked data for RequestSent events raised by the VRFv2Consumer contract. -type VRFv2ConsumerRequestSentIterator struct { - Event *VRFv2ConsumerRequestSent // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *VRFv2ConsumerRequestSentIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerRequestSent) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(VRFv2ConsumerRequestSent) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *VRFv2ConsumerRequestSentIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *VRFv2ConsumerRequestSentIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// VRFv2ConsumerRequestSent represents a RequestSent event raised by the VRFv2Consumer contract. -type VRFv2ConsumerRequestSent struct { - RequestId *big.Int - NumWords uint32 - Raw types.Log // Blockchain specific contextual infos -} - -// FilterRequestSent is a free log retrieval operation binding the contract event 0xcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee. -// -// Solidity: event RequestSent(uint256 requestId, uint32 numWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) FilterRequestSent(opts *bind.FilterOpts) (*VRFv2ConsumerRequestSentIterator, error) { - - logs, sub, err := _VRFv2Consumer.contract.FilterLogs(opts, "RequestSent") - if err != nil { - return nil, err - } - return &VRFv2ConsumerRequestSentIterator{contract: _VRFv2Consumer.contract, event: "RequestSent", logs: logs, sub: sub}, nil -} - -// WatchRequestSent is a free log subscription operation binding the contract event 0xcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee. -// -// Solidity: event RequestSent(uint256 requestId, uint32 numWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) WatchRequestSent(opts *bind.WatchOpts, sink chan<- *VRFv2ConsumerRequestSent) (event.Subscription, error) { - - logs, sub, err := _VRFv2Consumer.contract.WatchLogs(opts, "RequestSent") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(VRFv2ConsumerRequestSent) - if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestSent", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseRequestSent is a log parse operation binding the contract event 0xcc58b13ad3eab50626c6a6300b1d139cd6ebb1688a7cced9461c2f7e762665ee. -// -// Solidity: event RequestSent(uint256 requestId, uint32 numWords) -func (_VRFv2Consumer *VRFv2ConsumerFilterer) ParseRequestSent(log types.Log) (*VRFv2ConsumerRequestSent, error) { - event := new(VRFv2ConsumerRequestSent) - if err := _VRFv2Consumer.contract.UnpackLog(event, "RequestSent", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/integration-tests/contracts/ethereum/src/KeeperBase.sol b/integration-tests/contracts/ethereum/src/KeeperBase.sol deleted file mode 120000 index dfff3da022f..00000000000 --- a/integration-tests/contracts/ethereum/src/KeeperBase.sol +++ /dev/null @@ -1 +0,0 @@ -../../../../contracts/src/v0.7/KeeperBase.sol \ No newline at end of file diff --git a/integration-tests/contracts/ethereum/src/KeeperCompatibleInterface.sol b/integration-tests/contracts/ethereum/src/KeeperCompatibleInterface.sol deleted file mode 120000 index 8e6eb6cf21e..00000000000 --- a/integration-tests/contracts/ethereum/src/KeeperCompatibleInterface.sol +++ /dev/null @@ -1 +0,0 @@ -../../../../contracts/src/v0.7/interfaces/KeeperCompatibleInterface.sol \ No newline at end of file diff --git a/integration-tests/contracts/ethereum/src/KeeperConsumer.sol b/integration-tests/contracts/ethereum/src/KeeperConsumer.sol deleted file mode 100644 index 1c2d772e632..00000000000 --- a/integration-tests/contracts/ethereum/src/KeeperConsumer.sol +++ /dev/null @@ -1,31 +0,0 @@ -pragma solidity ^0.7.0; - -import "./KeeperCompatibleInterface.sol"; -import "./KeeperBase.sol"; - -contract KeeperConsumer is KeeperCompatibleInterface, KeeperBase { - uint public counter; - uint public immutable interval; - uint public lastTimeStamp; - - - constructor(uint updateInterval) public { - interval = updateInterval; - lastTimeStamp = block.timestamp; - counter = 0; - } - - function checkUpkeep(bytes calldata checkData) - external - override - view - cannotExecute - returns (bool upkeepNeeded, bytes memory performData) { - return (true, checkData); - } - - function performUpkeep(bytes calldata performData) external override { - counter = counter + 1; - } -} - diff --git a/integration-tests/contracts/ethereum/src/PerformDataChecker.sol b/integration-tests/contracts/ethereum/src/PerformDataChecker.sol deleted file mode 100644 index df63415d76b..00000000000 --- a/integration-tests/contracts/ethereum/src/PerformDataChecker.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.6; - -import "./KeeperCompatibleInterface.sol"; - -contract PerformDataChecker is KeeperCompatibleInterface { - uint256 public counter; - bytes public s_expectedData; - - constructor(bytes memory expectedData) { - s_expectedData = expectedData; - } - - function setExpectedData(bytes calldata expectedData) external { - s_expectedData = expectedData; - } - - function checkUpkeep(bytes calldata checkData) - external - view - override - returns (bool upkeepNeeded, bytes memory performData) - { - return (keccak256(checkData) == keccak256(s_expectedData), checkData); - } - - function performUpkeep(bytes calldata performData) external override { - if (keccak256(performData) == keccak256(s_expectedData)) { - counter++; - } - } -} diff --git a/integration-tests/contracts/ethereum/src/UpkeepCounter.sol b/integration-tests/contracts/ethereum/src/UpkeepCounter.sol deleted file mode 100644 index 3c42b58255f..00000000000 --- a/integration-tests/contracts/ethereum/src/UpkeepCounter.sol +++ /dev/null @@ -1,57 +0,0 @@ -pragma solidity ^0.7.6; - -contract UpkeepCounter { - event PerformingUpkeep( - address indexed from, - uint256 initialBlock, - uint256 lastBlock, - uint256 previousBlock, - uint256 counter - ); - - uint256 public testRange; - uint256 public interval; - uint256 public lastBlock; - uint256 public previousPerformBlock; - uint256 public initialBlock; - uint256 public counter; - - constructor(uint256 _testRange, uint256 _interval) { - testRange = _testRange; - interval = _interval; - previousPerformBlock = 0; - lastBlock = block.number; - initialBlock = 0; - counter = 0; - } - - function checkUpkeep(bytes calldata data) external view returns (bool, bytes memory) { - return (eligible(), data); - } - - function performUpkeep(bytes calldata performData) external { - if (initialBlock == 0) { - initialBlock = block.number; - } - lastBlock = block.number; - counter = counter + 1; - performData; - emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter); - previousPerformBlock = lastBlock; - } - - function eligible() public view returns (bool) { - if (initialBlock == 0) { - return true; - } - - return (block.number - initialBlock) < testRange && (block.number - lastBlock) >= interval; - } - - function setSpread(uint256 _testRange, uint256 _interval) external { - testRange = _testRange; - interval = _interval; - initialBlock = 0; - counter = 0; - } -} diff --git a/integration-tests/contracts/ethereum/src/VRFv2Consumer.sol b/integration-tests/contracts/ethereum/src/VRFv2Consumer.sol deleted file mode 100644 index 333318f4990..00000000000 --- a/integration-tests/contracts/ethereum/src/VRFv2Consumer.sol +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: MIT -// An example of a consumer contract that relies on a subscription for funding. -pragma solidity ^0.8.7; - -import "../../../../../contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; -import "../../../../../contracts/src/v0.8/VRFConsumerBaseV2.sol"; -import "../../../../contracts/src/v0.8/shared/access/ConfirmedOwner.sol"; - -/** - * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. - * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. - * DO NOT USE THIS CODE IN PRODUCTION. - */ - -contract VRFv2Consumer is VRFConsumerBaseV2, ConfirmedOwner { - event RequestSent(uint256 requestId, uint32 numWords); - event RequestFulfilled(uint256 requestId, uint256[] randomWords); - - struct RequestStatus { - bool fulfilled; // whether the request has been successfully fulfilled - bool exists; // whether a requestId exists - uint256[] randomWords; - } - mapping(uint256 => RequestStatus) - public s_requests; /* requestId --> requestStatus */ - VRFCoordinatorV2Interface COORDINATOR; - - // past requests Id. - uint256[] public requestIds; - uint256 public lastRequestId; - - constructor( - address vrfCoordinator - ) - VRFConsumerBaseV2(vrfCoordinator) - ConfirmedOwner(msg.sender) - { - COORDINATOR = VRFCoordinatorV2Interface( - vrfCoordinator - ); - } - - // Assumes the subscription is funded sufficiently. - function requestRandomWords( - uint64 subId, - uint32 callbackGasLimit, - uint16 requestConfirmations, - uint32 numWords, - bytes32 keyHash - ) - external - onlyOwner - returns (uint256 requestId) - { - // Will revert if subscription is not set and funded. - requestId = COORDINATOR.requestRandomWords( - keyHash, - subId, - requestConfirmations, - callbackGasLimit, - numWords - ); - s_requests[requestId] = RequestStatus({ - randomWords: new uint256[](0), - exists: true, - fulfilled: false - }); - requestIds.push(requestId); - lastRequestId = requestId; - emit RequestSent(requestId, numWords); - return requestId; - } - - function fulfillRandomWords( - uint256 _requestId, - uint256[] memory _randomWords - ) internal override { - require(s_requests[_requestId].exists, "request not found"); - s_requests[_requestId].fulfilled = true; - s_requests[_requestId].randomWords = _randomWords; - emit RequestFulfilled(_requestId, _randomWords); - } - - function getRequestStatus( - uint256 _requestId - ) external view returns (bool fulfilled, uint256[] memory randomWords) { - require(s_requests[_requestId].exists, "request not found"); - RequestStatus memory request = s_requests[_requestId]; - return (request.fulfilled, request.randomWords); - } -} diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index d3db6913c50..5b3a93fe0c2 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -5,27 +5,19 @@ import ( "encoding/hex" "fmt" "math/big" + "strings" "time" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" - ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" - - "strings" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink/integration-tests/client" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" @@ -47,8 +39,18 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/oracle_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/test_api_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/fee_manager" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/reward_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/werc20_mock" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" + ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" ) // EthereumOracle oracle for "directrequest" job tests @@ -63,7 +65,9 @@ func (e *EthereumOracle) Address() string { } func (e *EthereumOracle) Fund(ethAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -103,7 +107,9 @@ func (e *EthereumAPIConsumer) RoundID(ctx context.Context) (*big.Int, error) { } func (e *EthereumAPIConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -155,7 +161,9 @@ func (f *EthereumStaking) Address() string { // Fund sends specified currencies to the contract func (f *EthereumStaking) Fund(ethAmount *big.Float) error { - gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{ + To: f.address, + }) if err != nil { return err } @@ -899,7 +907,9 @@ func (f *EthereumFluxAggregator) Address() string { // Fund sends specified currencies to the contract func (f *EthereumFluxAggregator) Fund(ethAmount *big.Float) error { - gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := f.client.EstimateGas(ethereum.CallMsg{ + To: f.address, + }) if err != nil { return err } @@ -1190,7 +1200,9 @@ type EthereumLinkToken struct { // Fund the LINK Token contract with ETH to distribute the token func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { - gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{ + To: &l.address, + }) if err != nil { return err } @@ -1287,7 +1299,9 @@ type EthereumOffchainAggregator struct { // Fund sends specified currencies to the contract func (o *EthereumOffchainAggregator) Fund(ethAmount *big.Float) error { - gasEstimates, err := o.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := o.client.EstimateGas(ethereum.CallMsg{ + To: o.address, + }) if err != nil { return err } @@ -1957,7 +1971,9 @@ func (e *EthereumOffchainAggregatorV2) Address() string { } func (e *EthereumOffchainAggregatorV2) Fund(nativeAmount *big.Float) error { - gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := e.client.EstimateGas(ethereum.CallMsg{ + To: e.address, + }) if err != nil { return err } @@ -2235,10 +2251,7 @@ func (e *EthereumFunctionsLoadTestClient) ResetStats() error { if err != nil { return err } - if err := e.client.ProcessTransaction(tx); err != nil { - return err - } - return nil + return e.client.ProcessTransaction(tx) } func (e *EthereumFunctionsLoadTestClient) SendRequest(times uint32, source string, encryptedSecretsReferences []byte, args []string, subscriptionId uint64, jobId [32]byte) error { @@ -2269,10 +2282,11 @@ type EthereumMercuryVerifier struct { address common.Address client blockchain.EVMClient instance *verifier.Verifier + l zerolog.Logger } -func (e *EthereumMercuryVerifier) Address() string { - return e.address.Hex() +func (e *EthereumMercuryVerifier) Address() common.Address { + return e.address } func (e *EthereumMercuryVerifier) Verify(signedReport []byte, sender common.Address) error { @@ -2287,14 +2301,57 @@ func (e *EthereumMercuryVerifier) Verify(signedReport []byte, sender common.Addr return e.client.ProcessTransaction(tx) } +func (e *EthereumMercuryVerifier) SetConfig(feedId [32]byte, signers []common.Address, offchainTransmitters [][32]byte, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte, recipientAddressesAndWeights []verifier.CommonAddressAndWeight) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.SetConfig(opts, feedId, signers, offchainTransmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, recipientAddressesAndWeights) + e.l.Info().Err(err).Str("contractAddress", e.address.Hex()).Hex("feedId", feedId[:]).Msg("Called EthereumMercuryVerifier.SetConfig()") + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +func (e *EthereumMercuryVerifier) LatestConfigDetails(ctx context.Context, feedId [32]byte) (verifier.LatestConfigDetails, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(e.client.GetDefaultWallet().Address()), + Context: ctx, + } + d, err := e.instance.LatestConfigDetails(opts, feedId) + e.l.Info().Err(err).Str("contractAddress", e.address.Hex()).Hex("feedId", feedId[:]). + Interface("details", d). + Msg("Called EthereumMercuryVerifier.LatestConfigDetails()") + if err != nil { + return verifier.LatestConfigDetails{}, err + } + return d, nil +} + type EthereumMercuryVerifierProxy struct { address common.Address client blockchain.EVMClient instance *verifier_proxy.VerifierProxy + l zerolog.Logger } -func (e *EthereumMercuryVerifierProxy) Address() string { - return e.address.Hex() +func (e *EthereumMercuryVerifierProxy) Address() common.Address { + return e.address +} + +func (e *EthereumMercuryVerifierProxy) InitializeVerifier(verifierAddress common.Address) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.InitializeVerifier(opts, verifierAddress) + e.l.Info().Err(err).Str("contractAddress", e.address.Hex()).Str("verifierAddress", verifierAddress.Hex()). + Msg("Called EthereumMercuryVerifierProxy.InitializeVerifier()") + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) } func (e *EthereumMercuryVerifierProxy) Verify(signedReport []byte, parameterPayload []byte, value *big.Int) (*types.Transaction, error) { @@ -2305,7 +2362,7 @@ func (e *EthereumMercuryVerifierProxy) Verify(signedReport []byte, parameterPayl if err != nil { return nil, err } - tx, err := e.instance.Verify(opts, parameterPayload, signedReport) + tx, err := e.instance.Verify(opts, signedReport, parameterPayload) if err != nil { return nil, err } @@ -2326,3 +2383,126 @@ func (e *EthereumMercuryVerifierProxy) VerifyBulk(signedReports [][]byte, parame } return tx, e.client.ProcessTransaction(tx) } + +func (e *EthereumMercuryVerifierProxy) SetFeeManager(feeManager common.Address) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.SetFeeManager(opts, feeManager) + e.l.Info().Err(err).Str("feeManager", feeManager.Hex()).Msg("Called MercuryVerifierProxy.SetFeeManager()") + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +type EthereumMercuryFeeManager struct { + address common.Address + client blockchain.EVMClient + instance *fee_manager.FeeManager + l zerolog.Logger +} + +func (e *EthereumMercuryFeeManager) Address() common.Address { + return e.address +} + +type EthereumMercuryRewardManager struct { + address common.Address + client blockchain.EVMClient + instance *reward_manager.RewardManager + l zerolog.Logger +} + +func (e *EthereumMercuryRewardManager) Address() common.Address { + return e.address +} + +func (e *EthereumMercuryRewardManager) SetFeeManager(feeManager common.Address) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.SetFeeManager(opts, feeManager) + e.l.Info().Err(err).Str("feeManager", feeManager.Hex()).Msg("Called EthereumMercuryRewardManager.SetFeeManager()") + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + +type EthereumWERC20Mock struct { + address common.Address + client blockchain.EVMClient + instance *werc20_mock.WERC20Mock + l zerolog.Logger +} + +func (e *EthereumWERC20Mock) Address() common.Address { + return e.address +} + +func (e *EthereumWERC20Mock) Approve(to string, amount *big.Int) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + e.l.Info(). + Str("From", e.client.GetDefaultWallet().Address()). + Str("To", to). + Str("Amount", amount.String()). + Uint64("Nonce", opts.Nonce.Uint64()). + Msg("Approving LINK Transfer") + tx, err := e.instance.Approve(opts, common.HexToAddress(to), amount) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +func (e *EthereumWERC20Mock) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(e.client.GetDefaultWallet().Address()), + Context: ctx, + } + balance, err := e.instance.BalanceOf(opts, common.HexToAddress(addr)) + if err != nil { + return nil, err + } + return balance, nil +} + +func (e *EthereumWERC20Mock) Transfer(to string, amount *big.Int) error { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return err + } + e.l.Info(). + Str("From", e.client.GetDefaultWallet().Address()). + Str("To", to). + Str("Amount", amount.String()). + Uint64("Nonce", opts.Nonce.Uint64()). + Msg("EthereumWERC20Mock.Transfer()") + tx, err := e.instance.Transfer(opts, common.HexToAddress(to), amount) + if err != nil { + return err + } + return e.client.ProcessTransaction(tx) +} + +func (e *EthereumWERC20Mock) Mint(account common.Address, amount *big.Int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + e.l.Info(). + Str("account", account.Hex()). + Str("amount", amount.String()). + Msg("EthereumWERC20Mock.Mint()") + tx, err := e.instance.Mint(opts, account, amount) + if err != nil { + return tx, err + } + return tx, e.client.ProcessTransaction(tx) +} diff --git a/integration-tests/contracts/ethereum_contracts_local.go b/integration-tests/contracts/ethereum_contracts_local.go index aba6bc354e1..316658a791e 100644 --- a/integration-tests/contracts/ethereum_contracts_local.go +++ b/integration-tests/contracts/ethereum_contracts_local.go @@ -3,11 +3,13 @@ package contracts import ( "encoding/hex" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog/log" - "github.com/smartcontractkit/chainlink/integration-tests/client" ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting/types" + + "github.com/smartcontractkit/chainlink/integration-tests/client" ) // SetConfigLocal sets the payees and the offchain reporting protocol configuration diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index afb6550bd2c..135b016ee55 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -11,14 +11,15 @@ import ( geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" goabi "github.com/umbracle/ethgo/abi" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" @@ -31,12 +32,18 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper2_0" registry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_triggered_streams_lookup_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_upkeep_counter_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/perform_data_checker_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_upkeep_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_performance_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_counter_wrapper" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -45,7 +52,7 @@ var registrarABI = cltypes.MustGetABI(registrar21.AutomationRegistrarABI) type KeeperRegistrar interface { Address() string - EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool) ([]byte, error) + EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool, isMercury bool) ([]byte, error) Fund(ethAmount *big.Float) error } @@ -77,11 +84,12 @@ type KeeperRegistry interface { UnpauseUpkeep(id *big.Int) error UpdateCheckData(id *big.Int, newCheckData []byte) error SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) error + SetUpkeepPrivilegeConfig(id *big.Int, privilegeConfig []byte) error + RegistryOwnerAddress() common.Address } type KeeperConsumer interface { Address() string - Fund(ethAmount *big.Float) error Counter(ctx context.Context) (*big.Int, error) Start() error } @@ -219,7 +227,7 @@ func (v *EthereumKeeperRegistry) Fund(ethAmount *big.Float) error { return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) } -func (rcs *KeeperRegistrySettings) EncodeOnChainConfig(registrar string) ([]byte, error) { +func (rcs *KeeperRegistrySettings) EncodeOnChainConfig(registrar string, registryOwnerAddress common.Address) ([]byte, error) { if rcs.RegistryVersion == ethereum.RegistryVersion_2_1 { onchainConfigStruct := registry21.KeeperRegistryBase21OnchainConfig{ PaymentPremiumPPB: rcs.PaymentPremiumPPB, @@ -236,8 +244,9 @@ func (rcs *KeeperRegistrySettings) EncodeOnChainConfig(registrar string) ([]byte FallbackLinkPrice: rcs.FallbackLinkPrice, Transcoder: common.Address{}, Registrars: []common.Address{common.HexToAddress(registrar)}, - UpkeepPrivilegeManager: common.Address{}, + UpkeepPrivilegeManager: registryOwnerAddress, } + encodedOnchainConfig, err := utilsABI.Methods["_onChainConfig"].Inputs.Pack(&onchainConfigStruct) return encodedOnchainConfig, err @@ -262,6 +271,23 @@ func (rcs *KeeperRegistrySettings) EncodeOnChainConfig(registrar string) ([]byte } } +func (v *EthereumKeeperRegistry) RegistryOwnerAddress() common.Address { + callOpts := &bind.CallOpts{ + Pending: false, + } + + switch v.version { + case ethereum.RegistryVersion_2_1: + ownerAddress, _ := v.registry2_1.Owner(callOpts) + return ownerAddress + case ethereum.RegistryVersion_2_0: + ownerAddress, _ := v.registry2_0.Owner(callOpts) + return ownerAddress + } + + return common.HexToAddress(v.client.GetDefaultWallet().Address()) +} + func (v *EthereumKeeperRegistry) SetConfig(config KeeperRegistrySettings, ocrConfig OCRv2Config) error { txOpts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -925,6 +951,26 @@ func (v *EthereumKeeperRegistry) SetUpkeepTriggerConfig(id *big.Int, triggerConf } } +// SetUpkeepPrivilegeConfig sets the privilege config of an upkeep (only for version 2.1) +func (v *EthereumKeeperRegistry) SetUpkeepPrivilegeConfig(id *big.Int, privilegeConfig []byte) error { + + switch v.version { + case ethereum.RegistryVersion_2_1: + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + + tx, err := v.registry2_1.SetUpkeepPrivilegeConfig(opts, id, privilegeConfig) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) + default: + return fmt.Errorf("SetUpkeepPrivilegeConfig is not supported by keeper registry version %d", v.version) + } +} + // PauseUpkeep stops an upkeep from an upkeep func (v *EthereumKeeperRegistry) PauseUpkeep(id *big.Int) error { switch v.version { @@ -1356,13 +1402,13 @@ type KeeperConsumerBenchmarkRoundConfirmer struct { context context.Context cancel context.CancelFunc - firstBlockNum uint64 // Records the number of the first block that came in - lastBlockNum uint64 // Records the number of the last block that came in - blockRange int64 // How many blocks to watch upkeeps for - upkeepSLA int64 // SLA after which an upkeep is counted as 'missed' - metricsReporter *testreporters.KeeperBenchmarkTestReporter // Testreporter to track results - upkeepIndex int64 - firstEligibleuffer int64 + firstBlockNum uint64 // Records the number of the first block that came in + lastBlockNum uint64 // Records the number of the last block that came in + blockRange int64 // How many blocks to watch upkeeps for + upkeepSLA int64 // SLA after which an upkeep is counted as 'missed' + metricsReporter *testreporters.KeeperBenchmarkTestReporter // Testreporter to track results + upkeepIndex int64 + firstEligibleBuffer int64 // State variables, changes as we get blocks blocksSinceSubscription int64 // How many blocks have passed since subscribing @@ -1385,7 +1431,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( upkeepSLA int64, metricsReporter *testreporters.KeeperBenchmarkTestReporter, upkeepIndex int64, - firstEligibleuffer int64, + firstEligibleBuffer int64, logger zerolog.Logger, ) *KeeperConsumerBenchmarkRoundConfirmer { ctx, cancelFunc := context.WithCancel(context.Background()) @@ -1407,7 +1453,7 @@ func NewKeeperConsumerBenchmarkRoundConfirmer( lastBlockNum: 0, upkeepIndex: upkeepIndex, firstBlockNum: 0, - firstEligibleuffer: firstEligibleuffer, + firstEligibleBuffer: firstEligibleBuffer, l: logger, } } @@ -1458,7 +1504,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) ReceiveHeader(receivedHeader blo o.blocksSinceEligible = 0 } - isEligible, err := o.instance.CheckEligible(context.Background(), big.NewInt(o.upkeepIndex), big.NewInt(o.blockRange), big.NewInt(o.firstEligibleuffer)) + isEligible, err := o.instance.CheckEligible(context.Background(), big.NewInt(o.upkeepIndex), big.NewInt(o.blockRange), big.NewInt(o.firstEligibleBuffer)) if err != nil { return err } @@ -1552,7 +1598,7 @@ func (o *KeeperConsumerBenchmarkRoundConfirmer) logDetails() { // EthereumUpkeepCounter represents keeper consumer (upkeep) counter contract type EthereumUpkeepCounter struct { client blockchain.EVMClient - consumer *ethereum.UpkeepCounter + consumer *upkeep_counter_wrapper.UpkeepCounter address *common.Address } @@ -1594,7 +1640,7 @@ func (v *EthereumUpkeepCounter) SetSpread(testRange *big.Int, interval *big.Int) // EthereumUpkeepPerformCounterRestrictive represents keeper consumer (upkeep) counter contract type EthereumUpkeepPerformCounterRestrictive struct { client blockchain.EVMClient - consumer *ethereum.UpkeepPerformCounterRestrictive + consumer *upkeep_perform_counter_restrictive_wrapper.UpkeepPerformCounterRestrictive address *common.Address } @@ -1633,7 +1679,7 @@ func (v *EthereumUpkeepPerformCounterRestrictive) SetSpread(testRange *big.Int, // EthereumKeeperConsumer represents keeper consumer (upkeep) contract type EthereumKeeperConsumer struct { client blockchain.EVMClient - consumer *ethereum.KeeperConsumer + consumer *keeper_consumer_wrapper.KeeperConsumer address *common.Address } @@ -1646,15 +1692,44 @@ func (v *EthereumKeeperConsumer) Address() string { return v.address.Hex() } -func (v *EthereumKeeperConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(geth.CallMsg{}) +func (v *EthereumKeeperConsumer) Counter(ctx context.Context) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + cnt, err := v.consumer.Counter(opts) + if err != nil { + return nil, err + } + return cnt, nil +} + +type EthereumAutomationStreamsLookupUpkeepConsumer struct { + client blockchain.EVMClient + consumer *streams_lookup_upkeep_wrapper.StreamsLookupUpkeep + address *common.Address +} + +func (v *EthereumAutomationStreamsLookupUpkeepConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumAutomationStreamsLookupUpkeepConsumer) Start() error { + // For this consumer upkeep, we use this Start() function to set ParamKeys so as to run mercury v0.2 + txOpts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) + + // The default values of ParamKeys are "feedIDs" and "timestamp" which are for v0.3 + tx, err := v.consumer.SetParamKeys(txOpts, "feedIdHex", "blockNumber") + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) } -func (v *EthereumKeeperConsumer) Counter(ctx context.Context) (*big.Int, error) { +func (v *EthereumAutomationStreamsLookupUpkeepConsumer) Counter(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -1666,17 +1741,18 @@ func (v *EthereumKeeperConsumer) Counter(ctx context.Context) (*big.Int, error) return cnt, nil } -type EthereumAutomationLogCounterConsumer struct { +type EthereumAutomationLogTriggeredStreamsLookupUpkeepConsumer struct { client blockchain.EVMClient - consumer *log_upkeep_counter_wrapper.LogUpkeepCounter + consumer *log_triggered_streams_lookup_wrapper.LogTriggeredStreamsLookup address *common.Address } -func (v *EthereumAutomationLogCounterConsumer) Address() string { +func (v *EthereumAutomationLogTriggeredStreamsLookupUpkeepConsumer) Address() string { return v.address.Hex() } -func (v *EthereumAutomationLogCounterConsumer) Start() error { +// Kick off the log trigger event. The contract uses Mercury v0.2 so no need to set ParamKeys +func (v *EthereumAutomationLogTriggeredStreamsLookupUpkeepConsumer) Start() error { txOpts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -1689,12 +1765,39 @@ func (v *EthereumAutomationLogCounterConsumer) Start() error { return v.client.ProcessTransaction(tx) } -func (v *EthereumAutomationLogCounterConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(geth.CallMsg{}) +func (v *EthereumAutomationLogTriggeredStreamsLookupUpkeepConsumer) Counter(ctx context.Context) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + cnt, err := v.consumer.Counter(opts) + if err != nil { + return nil, err + } + return cnt, nil +} + +type EthereumAutomationLogCounterConsumer struct { + client blockchain.EVMClient + consumer *log_upkeep_counter_wrapper.LogUpkeepCounter + address *common.Address +} + +func (v *EthereumAutomationLogCounterConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumAutomationLogCounterConsumer) Start() error { + txOpts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) + + tx, err := v.consumer.Start(txOpts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) } func (v *EthereumAutomationLogCounterConsumer) Counter(ctx context.Context) (*big.Int, error) { @@ -1713,7 +1816,7 @@ func (v *EthereumAutomationLogCounterConsumer) Counter(ctx context.Context) (*bi // performance tests. type EthereumKeeperConsumerPerformance struct { client blockchain.EVMClient - consumer *ethereum.KeeperConsumerPerformance + consumer *keeper_consumer_performance_wrapper.KeeperConsumerPerformance address *common.Address } @@ -1774,7 +1877,7 @@ func (v *EthereumKeeperConsumerPerformance) SetPerformGasToBurn(ctx context.Cont // EthereumKeeperPerformDataCheckerConsumer represents keeper perform data checker contract type EthereumKeeperPerformDataCheckerConsumer struct { client blockchain.EVMClient - performDataChecker *ethereum.PerformDataChecker + performDataChecker *perform_data_checker_wrapper.PerformDataChecker address *common.Address } @@ -1867,7 +1970,7 @@ func (v *EthereumKeeperRegistrar) Fund(ethAmount *big.Float) error { } // EncodeRegisterRequest encodes register request to call it through link token TransferAndCall -func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool) ([]byte, error) { +func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byte, upkeepAddr string, gasLimit uint32, adminAddr string, checkData []byte, amount *big.Int, source uint8, senderAddr string, isLogTrigger bool, isMercury bool) ([]byte, error) { if v.registrar20 != nil { registryABI, err := abi.JSON(strings.NewReader(keeper_registrar_wrapper2_0.KeeperRegistrarMetaData.ABI)) if err != nil { @@ -1892,18 +1995,23 @@ func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byt return req, nil } else if v.registrar21 != nil { if isLogTrigger { - // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d - topic0InBytes := [32]byte{ - 61, 83, 163, 149, 80, 224, 70, 136, - 6, 88, 39, 243, 187, 134, 88, 76, - 176, 7, 171, 158, 188, 167, 235, - 213, 40, 231, 48, 28, 156, 49, 235, 93, - } - + var topic0InBytes [32]byte // bytes representation of 0x0000000000000000000000000000000000000000000000000000000000000000 bytes0 := [32]byte{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } + if isMercury { + // bytes representation of 0xd1ffe9e45581c11d7d9f2ed5f75217cd4be9f8b7eee6af0f6d03f46de53956cd + topic0InBytes = [32]byte{209, 255, 233, 228, 85, 129, 193, 29, 125, 159, 46, 213, 247, 82, 23, 205, 75, 233, 248, 183, 238, 230, 175, 15, 109, 3, 244, 109, 229, 57, 86, 205} + } else { + // bytes representation of 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d + topic0InBytes = [32]byte{ + 61, 83, 163, 149, 80, 224, 70, 136, + 6, 88, 39, 243, 187, 134, 88, 76, + 176, 7, 171, 158, 188, 167, 235, + 213, 40, 231, 48, 28, 156, 49, 235, 93, + } + } logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ ContractAddress: common.HexToAddress(upkeepAddr), @@ -1937,7 +2045,6 @@ func (v *EthereumKeeperRegistrar) EncodeRegisterRequest(name string, email []byt return nil, err } return req, nil - } else { req, err := registrarABI.Pack( "register", diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index 11606de53e5..e8149b21251 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -4,11 +4,15 @@ import ( "context" "encoding/hex" "fmt" + "math/big" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -16,8 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "math/big" - "time" ) // EthereumDKG represents DKG contract diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index f97ba86d975..427ac4ccbf8 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -13,7 +13,6 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" @@ -175,7 +174,9 @@ func (v *EthereumVRFConsumer) Address() string { } func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } @@ -277,7 +278,9 @@ func (f *VRFConsumerRoundConfirmer) Wait() error { // Fund sends specified currencies to the contract func (v *EthereumVRF) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index 88dfe58eb2f..9c7e628dbd9 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -3,17 +3,21 @@ package contracts import ( "context" "encoding/hex" + "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" - "math/big" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" ) // EthereumVRFCoordinatorV2 represents VRFV2 coordinator contract @@ -34,7 +38,7 @@ type EthereumVRFConsumerV2 struct { type EthereumVRFv2Consumer struct { address *common.Address client blockchain.EVMClient - consumer *eth_contracts.VRFv2Consumer + consumer *vrf_v2_consumer_wrapper.VRFv2Consumer } // EthereumVRFv2LoadTestConsumer represents VRFv2 consumer contract for performing Load Tests @@ -85,14 +89,14 @@ func (e *EthereumContractDeployer) DeployVRFv2Consumer(coordinatorAddr string) ( auth *bind.TransactOpts, backend bind.ContractBackend, ) (common.Address, *types.Transaction, interface{}, error) { - return eth_contracts.DeployVRFv2Consumer(auth, backend, common.HexToAddress(coordinatorAddr)) + return vrf_v2_consumer_wrapper.DeployVRFv2Consumer(auth, backend, common.HexToAddress(coordinatorAddr)) }) if err != nil { return nil, err } return &EthereumVRFv2Consumer{ client: e.client, - consumer: instance.(*eth_contracts.VRFv2Consumer), + consumer: instance.(*vrf_v2_consumer_wrapper.VRFv2Consumer), address: address, }, err } @@ -286,7 +290,9 @@ func (v *EthereumVRFConsumerV2) GasAvailable() (*big.Int, error) { } func (v *EthereumVRFConsumerV2) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } @@ -358,7 +364,7 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness(keyHash [32]byte, subI return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (RequestStatus, error) { +func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index d07492d0df1..df7cca54b2e 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" @@ -266,6 +267,26 @@ func (v *EthereumVRFCoordinatorV2_5) FindSubscriptionID() (*big.Int, error) { return subscriptionIterator.Event.SubId, nil } +func (v *EthereumVRFCoordinatorV2_5) WaitForSubscriptionCreatedEvent(timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated, error) { + eventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25SubscriptionCreated) + subscription, err := v.coordinator.WatchSubscriptionCreated(nil, eventsChannel, nil) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionCreated event") + case sub := <-eventsChannel: + return sub, nil + } + } +} + func (v *EthereumVRFCoordinatorV2_5) WaitForRandomWordsFulfilledEvent(subID []*big.Int, requestID []*big.Int, timeout time.Duration) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { randomWordsFulfilledEventsChannel := make(chan *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled) subscription, err := v.coordinator.WatchRandomWordsFulfilled(nil, randomWordsFulfilledEventsChannel, requestID, subID) @@ -342,6 +363,18 @@ func (v *EthereumVRFv2PlusLoadTestConsumer) RequestRandomness(keyHash [32]byte, return tx, v.client.ProcessTransaction(tx) } +func (v *EthereumVRFv2PlusLoadTestConsumer) ResetMetrics() error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.consumer.Reset(opts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFv2PlusLoadTestConsumer) GetCoordinator(ctx context.Context) (common.Address, error) { return v.consumer.SVrfCoordinator(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -745,7 +778,16 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error { +func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, + coordinatorGasOverhead uint32, + wrapperPremiumPercentage uint8, + keyHash [32]byte, + maxNumWords uint8, + stalenessSeconds uint32, + fallbackWeiPerUnitLink *big.Int, + fulfillmentFlatFeeLinkPPM uint32, + fulfillmentFlatFeeNativePPM uint32, +) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -757,6 +799,10 @@ func (v *EthereumVRFV2PlusWrapper) SetConfig(wrapperGasOverhead uint32, coordina wrapperPremiumPercentage, keyHash, maxNumWords, + stalenessSeconds, + fallbackWeiPerUnitLink, + fulfillmentFlatFeeLinkPPM, + fulfillmentFlatFeeNativePPM, ) if err != nil { return err @@ -772,7 +818,9 @@ func (v *EthereumVRFV2PlusWrapper) GetSubID(ctx context.Context) (*big.Int, erro } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { - gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ + To: v.address, + }) if err != nil { return err } @@ -820,7 +868,7 @@ func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetLastRequestId(ctx context. } func (v *EthereumVRFV2PlusWrapperLoadTestConsumer) GetWrapper(ctx context.Context) (common.Address, error) { - return v.consumer.GetWrapper(&bind.CallOpts{ + return v.consumer.IVrfV2PlusWrapper(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, }) diff --git a/integration-tests/docker/cmd/test_env.go b/integration-tests/docker/cmd/test_env.go index 1acf5947505..31b7de5dcdd 100644 --- a/integration-tests/docker/cmd/test_env.go +++ b/integration-tests/docker/cmd/test_env.go @@ -36,7 +36,7 @@ func main() { _, err := test_env.NewCLTestEnvBuilder(). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(6). Build() if err != nil { diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index e4182ca4c36..bf4d3285dcf 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -45,19 +45,23 @@ var ( type ClNode struct { test_env.EnvComponent - API *client.ChainlinkClient - NodeConfig *chainlink.Config - NodeSecretsConfigTOML string - PostgresDb *test_env.PostgresDb - lw *logwatch.LogWatch - ContainerImage string - ContainerVersion string + API *client.ChainlinkClient `json:"-"` + NodeConfig *chainlink.Config `json:"-"` + NodeSecretsConfigTOML string `json:"-"` + PostgresDb *test_env.PostgresDb `json:"postgresDb"` t *testing.T l zerolog.Logger + lw *logwatch.LogWatch } type ClNodeOption = func(c *ClNode) +func WithSecrets(secretsTOML string) ClNodeOption { + return func(c *ClNode) { + c.NodeSecretsConfigTOML = secretsTOML + } +} + // Sets custom node container name if name is not empty func WithNodeContainerName(name string) ClNodeOption { return func(c *ClNode) { @@ -101,11 +105,10 @@ func NewClNode(networks []string, nodeConfig *chainlink.Config, opts ...ClNodeOp return n } -func (n *ClNode) WithTestLogger(t *testing.T) *ClNode { +func (n *ClNode) SetTestLogger(t *testing.T) { n.l = logging.GetTestLogger(t) n.t = t n.PostgresDb.WithTestLogger(t) - return n } // Restart restarts only CL node, DB container is reused @@ -226,28 +229,35 @@ func (n *ClNode) Fund(evmClient blockchain.EVMClient, amount *big.Float) error { if err != nil { return err } - gasEstimates, err := evmClient.EstimateGas(ethereum.CallMsg{}) + toAddr := common.HexToAddress(toAddress) + gasEstimates, err := evmClient.EstimateGas(ethereum.CallMsg{ + To: &toAddr, + }) if err != nil { return err } return evmClient.Fund(toAddress, amount, gasEstimates) } + func (n *ClNode) StartContainer() error { err := n.PostgresDb.StartContainer() if err != nil { return err } + + // If the node secrets TOML is not set, generate it with the default template nodeSecretsToml, err := templates.NodeSecretsTemplate{ - PgDbName: n.PostgresDb.DbName, - PgHost: n.PostgresDb.ContainerName, - PgPort: n.PostgresDb.Port, - PgPassword: n.PostgresDb.Password, + PgDbName: n.PostgresDb.DbName, + PgHost: n.PostgresDb.ContainerName, + PgPort: n.PostgresDb.InternalPort, + PgPassword: n.PostgresDb.Password, + CustomSecrets: n.NodeSecretsConfigTOML, }.String() if err != nil { return err } - n.NodeSecretsConfigTOML = nodeSecretsToml - cReq, err := n.getContainerRequest() + + cReq, err := n.getContainerRequest(nodeSecretsToml) if err != nil { return err } @@ -273,7 +283,7 @@ func (n *ClNode) StartContainer() error { return err } } - clEndpoint, err := container.Endpoint(context.Background(), "http") + clEndpoint, err := test_env.GetEndpoint(context.Background(), container, "http") if err != nil { return err } @@ -302,7 +312,7 @@ func (n *ClNode) StartContainer() error { return nil } -func (n *ClNode) getContainerRequest() ( +func (n *ClNode) getContainerRequest(secrets string) ( *tc.ContainerRequest, error) { configFile, err := os.CreateTemp("", "node_config") if err != nil { @@ -320,7 +330,7 @@ func (n *ClNode) getContainerRequest() ( if err != nil { return nil, err } - _, err = secretsFile.WriteString(n.NodeSecretsConfigTOML) + _, err = secretsFile.WriteString(secrets) if err != nil { return nil, err } @@ -376,7 +386,7 @@ func (n *ClNode) getContainerRequest() ( "-p", adminCredsPath, "-a", apiCredsPath, }, - Networks: n.Networks, + Networks: append(n.Networks, "tracing"), WaitingFor: tcwait.ForHTTP("/health"). WithPort("6688/tcp"). WithStartupTimeout(90 * time.Second). diff --git a/integration-tests/docker/test_env/cl_node_cluster.go b/integration-tests/docker/test_env/cl_node_cluster.go new file mode 100644 index 00000000000..a717a192649 --- /dev/null +++ b/integration-tests/docker/test_env/cl_node_cluster.go @@ -0,0 +1,68 @@ +package test_env + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "golang.org/x/sync/errgroup" +) + +var ( + ErrGetNodeCSAKeys = "failed get CL node CSA keys" +) + +type ClCluster struct { + Nodes []*ClNode `json:"nodes"` +} + +// Start all nodes in the cluster./docker/tests/functional/api +func (c *ClCluster) Start() error { + eg := &errgroup.Group{} + nodes := c.Nodes + + for i := 0; i < len(nodes); i++ { + nodeIndex := i + eg.Go(func() error { + err := nodes[nodeIndex].StartContainer() + if err != nil { + return err + } + return nil + }) + } + + return eg.Wait() +} + +func (c *ClCluster) NodeAPIs() []*client.ChainlinkClient { + clients := make([]*client.ChainlinkClient, 0) + for _, c := range c.Nodes { + clients = append(clients, c.API) + } + return clients +} + +// Return all the on-chain wallet addresses for a set of Chainlink nodes +func (c *ClCluster) NodeAddresses() ([]common.Address, error) { + addresses := make([]common.Address, 0) + for _, n := range c.Nodes { + primaryAddress, err := n.ChainlinkNodeAddress() + if err != nil { + return nil, err + } + addresses = append(addresses, primaryAddress) + } + return addresses, nil +} + +func (c *ClCluster) NodeCSAKeys() ([]string, error) { + var keys []string + for _, n := range c.Nodes { + csaKeys, err := n.GetNodeCSAKeys() + if err != nil { + return nil, errors.Wrap(err, ErrGetNodeCSAKeys) + } + keys = append(keys, csaKeys.Data[0].ID) + } + return keys, nil +} diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 8c4faadbd2b..9eb9ed9f39b 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -12,7 +12,6 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -24,16 +23,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/logwatch" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" ) var ( - ErrFundCLNode = "failed to fund CL node" - ErrGetNodeCSAKeys = "failed get CL node CSA keys" + ErrFundCLNode = "failed to fund CL node" ) type CLClusterTestEnv struct { @@ -42,10 +40,10 @@ type CLClusterTestEnv struct { LogWatch *logwatch.LogWatch /* components */ - CLNodes []*ClNode + ClCluster *ClCluster Geth *test_env.Geth // for tests using --dev networks PrivateChain []test_env.PrivateChain // for tests using non-dev networks - MockServer *test_env.MockServer + MockAdapter *test_env.Killgrave EVMClient blockchain.EVMClient ContractDeployer contracts.ContractDeployer ContractLoader contracts.ContractLoader @@ -59,40 +57,33 @@ func NewTestEnv() (*CLClusterTestEnv, error) { if err != nil { return nil, err } - networks := []string{network.Name} + n := []string{network.Name} return &CLClusterTestEnv{ - Network: network, - Geth: test_env.NewGeth(networks), - MockServer: test_env.NewMockServer(networks), - l: log.Logger, + Geth: test_env.NewGeth(n), + MockAdapter: test_env.NewKillgrave(n, ""), + Network: network, + l: log.Logger, }, nil } +// WithTestEnvConfig sets the test environment cfg. +// Sets up the Geth and MockAdapter containers with the provided cfg. +func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTestEnv { + te.Cfg = cfg + n := []string{te.Network.Name} + te.Geth = test_env.NewGeth(n, test_env.WithContainerName(te.Cfg.Geth.ContainerName)) + te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) + return te +} + func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { te.t = t te.l = logging.GetTestLogger(t) te.Geth.WithTestLogger(t) - te.MockServer.WithTestLogger(t) + te.MockAdapter.WithTestLogger(t) return te } -func NewTestEnvFromCfg(l zerolog.Logger, cfg *TestEnvConfig) (*CLClusterTestEnv, error) { - utils.SetupCoreDockerEnvLogger() - network, err := docker.CreateNetwork(log.Logger) - if err != nil { - return nil, err - } - networks := []string{network.Name} - l.Info().Interface("Cfg", cfg).Send() - return &CLClusterTestEnv{ - Cfg: cfg, - Network: network, - Geth: test_env.NewGeth(networks, test_env.WithContainerName(cfg.Geth.ContainerName)), - MockServer: test_env.NewMockServer(networks, test_env.WithContainerName(cfg.MockServer.ContainerName)), - l: log.Logger, - }, nil -} - func (te *CLClusterTestEnv) ParallelTransactions(enabled bool) { te.EVMClient.ParallelTransactions(enabled) } @@ -123,7 +114,7 @@ func (te *CLClusterTestEnv) StartPrivateChain() error { for _, chain := range te.PrivateChain { primaryNode := chain.GetPrimaryNode() if primaryNode == nil { - return errors.WithStack(fmt.Errorf("Primary node is nil in PrivateChain interface")) + return errors.WithStack(fmt.Errorf("primary node is nil in PrivateChain interface")) } err := primaryNode.Start() if err != nil { @@ -141,76 +132,37 @@ func (te *CLClusterTestEnv) StartGeth() (blockchain.EVMNetwork, test_env.Interna return te.Geth.StartContainer() } -func (te *CLClusterTestEnv) StartMockServer() error { - return te.MockServer.StartContainer() -} - -func (te *CLClusterTestEnv) GetAPIs() []*client.ChainlinkClient { - clients := make([]*client.ChainlinkClient, 0) - for _, c := range te.CLNodes { - clients = append(clients, c.API) - } - return clients +func (te *CLClusterTestEnv) StartMockAdapter() error { + return te.MockAdapter.StartContainer() } -// StartClNodes start one bootstrap node and {count} OCR nodes -func (te *CLClusterTestEnv) StartClNodes(nodeConfig *chainlink.Config, count int) error { - eg := &errgroup.Group{} - nodes := make(chan *ClNode, count) - - // Start nodes - for i := 0; i < count; i++ { - nodeIndex := i - eg.Go(func() error { - var nodeContainerName, dbContainerName string - if te.Cfg != nil { - nodeContainerName = te.Cfg.Nodes[nodeIndex].NodeContainerName - dbContainerName = te.Cfg.Nodes[nodeIndex].DbContainerName - } - n := NewClNode([]string{te.Network.Name}, nodeConfig, - WithNodeContainerName(nodeContainerName), - WithDbContainerName(dbContainerName), +func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string) error { + if te.Cfg != nil && te.Cfg.ClCluster != nil { + te.ClCluster = te.Cfg.ClCluster + } else { + te.ClCluster = &ClCluster{} + for i := 0; i < count; i++ { + ocrNode := NewClNode([]string{te.Network.Name}, nodeConfig, + WithSecrets(secretsConfig), ) - if te.t != nil { - n.WithTestLogger(te.t) - } - err := n.StartContainer() - if err != nil { - return err - } - nodes <- n - return nil - }) - } - - if err := eg.Wait(); err != nil { - return err - } - close(nodes) - - for node := range nodes { - te.CLNodes = append(te.CLNodes, node) + te.ClCluster.Nodes = append(te.ClCluster.Nodes, ocrNode) + } } - return nil -} - -// ChainlinkNodeAddresses will return all the on-chain wallet addresses for a set of Chainlink nodes -func (te *CLClusterTestEnv) ChainlinkNodeAddresses() ([]common.Address, error) { - addresses := make([]common.Address, 0) - for _, n := range te.CLNodes { - primaryAddress, err := n.ChainlinkNodeAddress() - if err != nil { - return nil, err + // Set test logger + if te.t != nil { + for _, n := range te.ClCluster.Nodes { + n.SetTestLogger(te.t) } - addresses = append(addresses, primaryAddress) } - return addresses, nil + + // Start/attach node containers + return te.ClCluster.Start() } // FundChainlinkNodes will fund all the provided Chainlink nodes with a set amount of native currency func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { - for _, cl := range te.CLNodes { + for _, cl := range te.ClCluster.Nodes { if err := cl.Fund(te.EVMClient, amount); err != nil { return errors.Wrap(err, ErrFundCLNode) } @@ -218,77 +170,61 @@ func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { return te.EVMClient.WaitForEvents() } -func (te *CLClusterTestEnv) GetNodeCSAKeys() ([]string, error) { - var keys []string - for _, n := range te.CLNodes { - csaKeys, err := n.GetNodeCSAKeys() - if err != nil { - return nil, errors.Wrap(err, ErrGetNodeCSAKeys) - } - keys = append(keys, csaKeys.Data[0].ID) - } - return keys, nil -} - func (te *CLClusterTestEnv) Terminate() error { // TESTCONTAINERS_RYUK_DISABLED=false by default so ryuk will remove all // the containers and the Network return nil } -// Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks. -// Intended to be used as part of t.Cleanup() in tests. -func (te *CLClusterTestEnv) Cleanup(t *testing.T) error { - if te.EVMClient == nil { - return errors.New("blockchain client is nil, unable to return funds from chainlink nodes") +// Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks and logs. +func (te *CLClusterTestEnv) Cleanup() error { + te.l.Info().Msg("Cleaning up test environment") + if te.t == nil { + return errors.New("cannot cleanup test environment without a testing.T") } - if te.CLNodes == nil { - return errors.New("chainlink nodes are nil, unable to return funds from chainlink nodes") + if te.ClCluster == nil || len(te.ClCluster.Nodes) == 0 { + return errors.New("chainlink nodes are nil, unable cleanup chainlink nodes") } - // Check if we need to return funds - if te.EVMClient.NetworkSimulated() { - te.l.Info().Str("Network Name", te.EVMClient.GetNetworkName()). + // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution + // Collect logs if the test fails, or if we just want them + if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { + if err := te.collectTestLogs(); err != nil { + return err + } + } + + if te.EVMClient == nil { + return errors.New("evm client is nil, unable to return funds from chainlink nodes during cleanup") + } else if te.EVMClient.NetworkSimulated() { + te.l.Info(). + Str("Network Name", te.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return.") } else { - te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") - for _, chainlinkNode := range te.CLNodes { - fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) - if err != nil { - return err - } - for _, key := range fundedKeys { - keyToDecrypt, err := json.Marshal(key) - if err != nil { - return err - } - // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM - // issues. So we avoid running in parallel; slower, but safer. - decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) - if err != nil { - return err - } - if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { - return err - } - } + if err := te.returnFunds(); err != nil { + return err } } - // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution - // Collect logs if the test failed - if !t.Failed() { - return nil + // close EVMClient connections + if te.EVMClient != nil { + err := te.EVMClient.Close() + return err } - folder := fmt.Sprintf("./logs/%s-%s", t.Name(), time.Now().Format("2006-01-02T15-04-05")) + return nil +} + +// collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files +func (te *CLClusterTestEnv) collectTestLogs() error { + te.l.Info().Msg("Collecting test logs") + folder := fmt.Sprintf("./logs/%s-%s", te.t.Name(), time.Now().Format("2006-01-02T15-04-05")) if err := os.MkdirAll(folder, os.ModePerm); err != nil { return err } - te.l.Warn().Msg("Test failed, collecting logs") eg := &errgroup.Group{} - for _, n := range te.CLNodes { + for _, n := range te.ClCluster.Nodes { node := n eg.Go(func() error { logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) @@ -314,7 +250,35 @@ func (te *CLClusterTestEnv) Cleanup(t *testing.T) error { return err } - te.l.Info().Str("Logs Location", folder).Msg("Wrote Logs for Failed Test") + te.l.Info().Str("Logs Location", folder).Msg("Wrote test logs") + return nil +} + +func (te *CLClusterTestEnv) returnFunds() error { + te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") + for _, chainlinkNode := range te.ClCluster.Nodes { + fundedKeys, err := chainlinkNode.API.ExportEVMKeysForChain(te.EVMClient.GetChainID().String()) + if err != nil { + return err + } + for _, key := range fundedKeys { + keyToDecrypt, err := json.Marshal(key) + if err != nil { + return err + } + // This can take up a good bit of RAM and time. When running on the remote-test-runner, this can lead to OOM + // issues. So we avoid running in parallel; slower, but safer. + decryptedKey, err := keystore.DecryptKey(keyToDecrypt, client.ChainlinkKeyPassword) + if err != nil { + return err + } + if err = te.EVMClient.ReturnFunds(decryptedKey.PrivateKey); err != nil { + // If we fail to return funds from one, go on to try the others anyway + te.l.Error().Err(err).Str("Node", chainlinkNode.ContainerName).Msg("Error returning funds from node") + } + } + } + te.l.Info().Msg("Returned funds from Chainlink nodes") return nil } diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index f3944b0ba96..072728321bf 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -21,19 +21,31 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" ) +type CleanUpType string + +const ( + CleanUpTypeNone CleanUpType = "none" + CleanUpTypeStandard CleanUpType = "standard" + CleanUpTypeCustom CleanUpType = "custom" +) + type CLTestEnvBuilder struct { - hasLogWatch bool - hasGeth bool - hasMockServer bool - hasForwarders bool - clNodeConfig *chainlink.Config - nonDevGethNetworks []blockchain.EVMNetwork - clNodesCount int - externalAdapterCount int - customNodeCsaKeys []string - defaultNodeCsaKeys []string - l zerolog.Logger - t *testing.T + hasLogWatch bool + hasGeth bool + hasKillgrave bool + hasForwarders bool + clNodeConfig *chainlink.Config + secretsConfig string + nonDevGethNetworks []blockchain.EVMNetwork + clNodesCount int + customNodeCsaKeys []string + defaultNodeCsaKeys []string + l zerolog.Logger + t *testing.T + te *CLClusterTestEnv + isNonEVM bool + cleanUpType CleanUpType + cleanUpCustomFn func() /* funding */ ETHFunds *big.Float @@ -41,11 +53,42 @@ type CLTestEnvBuilder struct { func NewCLTestEnvBuilder() *CLTestEnvBuilder { return &CLTestEnvBuilder{ - externalAdapterCount: 1, - l: log.Logger, + l: log.Logger, } } +// WithTestEnv sets the test environment to use for the test. +// If nil, a new test environment is created. +// If not nil, the test environment is used as-is. +// If TEST_ENV_CONFIG_PATH is set, the test environment is created with the config at that path. +func (b *CLTestEnvBuilder) WithTestEnv(te *CLClusterTestEnv) (*CLTestEnvBuilder, error) { + envConfigPath, isSet := os.LookupEnv("TEST_ENV_CONFIG_PATH") + var cfg *TestEnvConfig + var err error + if isSet { + cfg, err = NewTestEnvConfigFromFile(envConfigPath) + if err != nil { + return nil, err + } + } + + if te != nil { + b.te = te + } else { + b.te, err = NewTestEnv() + if err != nil { + return nil, err + } + } + + if cfg != nil { + b.te = b.te.WithTestEnvConfig(cfg) + } + return b, nil +} + +// WithTestLogger sets the test logger to use for the test. +// Useful for parallel tests so the logging will be separated correctly in the results views. func (b *CLTestEnvBuilder) WithTestLogger(t *testing.T) *CLTestEnvBuilder { b.t = t b.l = logging.GetTestLogger(t) @@ -87,81 +130,99 @@ func (b *CLTestEnvBuilder) WithCLNodeConfig(cfg *chainlink.Config) *CLTestEnvBui return b } -func (b *CLTestEnvBuilder) WithMockServer(externalAdapterCount int) *CLTestEnvBuilder { - b.hasMockServer = true - b.externalAdapterCount = externalAdapterCount +func (b *CLTestEnvBuilder) WithSecretsConfig(secrets string) *CLTestEnvBuilder { + b.secretsConfig = secrets + return b +} + +func (b *CLTestEnvBuilder) WithMockAdapter() *CLTestEnvBuilder { + b.hasKillgrave = true + return b +} + +// WithNonEVM sets the test environment to not use EVM when built. +func (b *CLTestEnvBuilder) WithNonEVM() *CLTestEnvBuilder { + b.isNonEVM = true + return b +} + +func (b *CLTestEnvBuilder) WithStandardCleanup() *CLTestEnvBuilder { + b.cleanUpType = CleanUpTypeStandard + return b +} + +func (b *CLTestEnvBuilder) WithoutCleanup() *CLTestEnvBuilder { + b.cleanUpType = CleanUpTypeNone + return b +} + +func (b *CLTestEnvBuilder) WithCustomCleanup(customFn func()) *CLTestEnvBuilder { + b.cleanUpType = CleanUpTypeCustom + b.cleanUpCustomFn = customFn return b } func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { - envConfigPath, isSet := os.LookupEnv("TEST_ENV_CONFIG_PATH") - if isSet { - cfg, err := NewTestEnvConfigFromFile(envConfigPath) + if b.te == nil { + var err error + b, err = b.WithTestEnv(nil) if err != nil { return nil, err } - _ = os.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true") - return b.buildNewEnv(cfg) } - return b.buildNewEnv(nil) -} - -func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, error) { b.l.Info(). Bool("hasGeth", b.hasGeth). - Bool("hasMockServer", b.hasMockServer). - Int("externalAdapterCount", b.externalAdapterCount). + Bool("hasKillgrave", b.hasKillgrave). Int("clNodesCount", b.clNodesCount). Strs("customNodeCsaKeys", b.customNodeCsaKeys). Strs("defaultNodeCsaKeys", b.defaultNodeCsaKeys). Msg("Building CL cluster test environment..") - var te *CLClusterTestEnv var err error - if cfg != nil { - te, err = NewTestEnvFromCfg(b.l, cfg) - if err != nil { - return nil, err - } - } else { - te, err = NewTestEnv() - if err != nil { - return nil, err - } - } - if b.t != nil { - te.WithTestLogger(b.t) + b.te.WithTestLogger(b.t) } if b.hasLogWatch { - te.LogWatch, err = logwatch.NewLogWatch(nil, nil) + b.te.LogWatch, err = logwatch.NewLogWatch(nil, nil) if err != nil { return nil, err } } - if b.hasMockServer { - err = te.StartMockServer() - if err != nil { - return nil, err - } - err = te.MockServer.SetExternalAdapterMocks(b.externalAdapterCount) + if b.hasKillgrave { + err = b.te.StartMockAdapter() if err != nil { return nil, err } } + + switch b.cleanUpType { + case CleanUpTypeStandard: + b.t.Cleanup(func() { + if err := b.te.Cleanup(); err != nil { + b.l.Error().Err(err).Msg("Error cleaning up test environment") + } + }) + case CleanUpTypeCustom: + b.t.Cleanup(b.cleanUpCustomFn) + case CleanUpTypeNone: + b.l.Warn().Msg("test environment won't be cleaned up") + case "": + return b.te, errors.WithMessage(errors.New("explicit cleanup type must be set when building test environment"), "test environment builder failed") + } + if b.nonDevGethNetworks != nil { - te.WithPrivateChain(b.nonDevGethNetworks) - err := te.StartPrivateChain() + b.te.WithPrivateChain(b.nonDevGethNetworks) + err := b.te.StartPrivateChain() if err != nil { - return te, err + return b.te, err } var nonDevNetworks []blockchain.EVMNetwork - for i, n := range te.PrivateChain { + for i, n := range b.te.PrivateChain { primaryNode := n.GetPrimaryNode() if primaryNode == nil { - return te, errors.WithStack(fmt.Errorf("Primary node is nil in PrivateChain interface")) + return b.te, errors.WithStack(fmt.Errorf("primary node is nil in PrivateChain interface")) } nonDevNetworks = append(nonDevNetworks, *n.GetNetworkConfig()) nonDevNetworks[i].URLs = []string{primaryNode.GetInternalWsUrl()} @@ -171,40 +232,41 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e return nil, errors.New("cannot create nodes with custom config without nonDevNetworks") } - err = te.StartClNodes(b.clNodeConfig, b.clNodesCount) + err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig) if err != nil { return nil, err } - return te, nil + return b.te, nil } networkConfig := networks.SelectedNetwork var internalDockerUrls test_env.InternalDockerUrls if b.hasGeth && networkConfig.Simulated { - networkConfig, internalDockerUrls, err = te.StartGeth() + networkConfig, internalDockerUrls, err = b.te.StartGeth() if err != nil { return nil, err } } - bc, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) - if err != nil { - return nil, err - } - - te.EVMClient = bc + if !b.isNonEVM { + bc, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) + if err != nil { + return nil, err + } - cd, err := contracts.NewContractDeployer(bc, b.l) - if err != nil { - return nil, err - } - te.ContractDeployer = cd + b.te.EVMClient = bc + cd, err := contracts.NewContractDeployer(bc, b.l) + if err != nil { + return nil, err + } + b.te.ContractDeployer = cd - cl, err := contracts.NewContractLoader(bc, b.l) - if err != nil { - return nil, err + cl, err := contracts.NewContractLoader(bc, b.l) + if err != nil { + return nil, err + } + b.te.ContractLoader = cl } - te.ContractLoader = cl var nodeCsaKeys []string @@ -219,26 +281,27 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e node.WithP2Pv1(), ) } - //node.SetDefaultSimulatedGeth(cfg, te.Geth.InternalWsUrl, te.Geth.InternalHttpUrl, b.hasForwarders) - var httpUrls []string - var wsUrls []string - if networkConfig.Simulated { - httpUrls = []string{internalDockerUrls.HttpUrl} - wsUrls = []string{internalDockerUrls.WsUrl} - } else { - httpUrls = networkConfig.HTTPURLs - wsUrls = networkConfig.URLs - } + if !b.isNonEVM { + var httpUrls []string + var wsUrls []string + if networkConfig.Simulated { + httpUrls = []string{internalDockerUrls.HttpUrl} + wsUrls = []string{internalDockerUrls.WsUrl} + } else { + httpUrls = networkConfig.HTTPURLs + wsUrls = networkConfig.URLs + } - node.SetChainConfig(cfg, wsUrls, httpUrls, networkConfig, b.hasForwarders) + node.SetChainConfig(cfg, wsUrls, httpUrls, networkConfig, b.hasForwarders) + } - err := te.StartClNodes(cfg, b.clNodesCount) + err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig) if err != nil { return nil, err } - nodeCsaKeys, err = te.GetNodeCSAKeys() + nodeCsaKeys, err = b.te.ClCluster.NodeCSAKeys() if err != nil { return nil, err } @@ -246,12 +309,12 @@ func (b *CLTestEnvBuilder) buildNewEnv(cfg *TestEnvConfig) (*CLClusterTestEnv, e } if b.hasGeth && b.clNodesCount > 0 && b.ETHFunds != nil { - te.ParallelTransactions(true) - defer te.ParallelTransactions(false) - if err := te.FundChainlinkNodes(b.ETHFunds); err != nil { + b.te.ParallelTransactions(true) + defer b.te.ParallelTransactions(false) + if err := b.te.FundChainlinkNodes(b.ETHFunds); err != nil { return nil, err } } - return te, nil + return b.te, nil } diff --git a/integration-tests/docker/test_env/test_env_config.go b/integration-tests/docker/test_env/test_env_config.go index da38575a86a..1a0c8d5c86a 100644 --- a/integration-tests/docker/test_env/test_env_config.go +++ b/integration-tests/docker/test_env/test_env_config.go @@ -7,26 +7,21 @@ import ( ) type TestEnvConfig struct { - Networks []string `json:"networks"` - Geth GethConfig `json:"geth"` - MockServer MockServerConfig `json:"mockserver"` - Nodes []ClNodeConfig `json:"nodes"` + Networks []string `json:"networks"` + Geth GethConfig `json:"geth"` + MockAdapter MockAdapterConfig `json:"mock_adapter"` + ClCluster *ClCluster `json:"clCluster"` } -type MockServerConfig struct { - ContainerName string `json:"container_name"` - EAMockUrls []string `json:"external_adapters_mock_urls"` +type MockAdapterConfig struct { + ContainerName string `json:"container_name"` + ImpostersPath string `json:"imposters_path"` } type GethConfig struct { ContainerName string `json:"container_name"` } -type ClNodeConfig struct { - NodeContainerName string `json:"container_name"` - DbContainerName string `json:"db_container_name"` -} - func NewTestEnvConfigFromFile(path string) (*TestEnvConfig, error) { c := &TestEnvConfig{} err := env.ParseJSONFile(path, c) diff --git a/integration-tests/example.env b/integration-tests/example.env index 428f76b914e..3e27ac2c7ab 100644 --- a/integration-tests/example.env +++ b/integration-tests/example.env @@ -2,11 +2,11 @@ # `source ./integration-tests/.env` ########## General Test Settings ########## -export KEEP_ENVIRONMENTS="Never" # Always | OnFail | Never export CHAINLINK_IMAGE="public.ecr.aws/chainlink/chainlink" # Image repo to pull the Chainlink image from export CHAINLINK_VERSION="2.4.0" # Version of the Chainlink image to pull export CHAINLINK_ENV_USER="Satoshi-Nakamoto" # Name of the person running the tests (change to your own) export TEST_LOG_LEVEL="info" # info | debug | trace +export TEST_LOG_COLLECT="false" # true | false, whether to collect the test logs after the test is complete, this will always be done if the test fails, regardless of this setting ########## Soak/Chaos/Load Test Specific Settings ########## # Remote Runner diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 9aa09350013..7dd2d017785 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -18,11 +18,12 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 + github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-env v0.36.0 - github.com/smartcontractkit/chainlink-testing-framework v1.17.0 + github.com/smartcontractkit/chainlink-env v0.38.3 + github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 @@ -32,8 +33,8 @@ require ( github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 - go.uber.org/zap v1.25.0 - golang.org/x/sync v0.3.0 + go.uber.org/zap v1.26.0 + golang.org/x/sync v0.4.0 gopkg.in/guregu/null.v4 v4.0.0 ) @@ -70,11 +71,10 @@ require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/avast/retry-go/v4 v4.5.0 // indirect - github.com/aws/aws-sdk-go v1.44.276 // indirect + github.com/aws/aws-sdk-go v1.44.302 // 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.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blendle/zapdriver v1.3.1 // indirect @@ -130,7 +130,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/esote/minmaxheap v1.0.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect @@ -159,7 +159,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.3 // 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/loads v0.21.2 // indirect @@ -203,25 +203,26 @@ require ( github.com/grafana/dskit v0.0.0-20230201083518-528d8a7d52f2 // indirect github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 // indirect github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 // indirect - github.com/grafana/pyroscope-go v1.0.2 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.3 // indirect + github.com/grafana/pyroscope-go v1.0.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // 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.0-rc.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.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.21.0 // indirect + github.com/hashicorp/consul/api v1.22.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // 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/go-plugin v1.4.10 // indirect + github.com/hashicorp/go-plugin v1.5.2 // 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 @@ -260,7 +261,7 @@ require ( 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/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -313,7 +314,7 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.54 // indirect + github.com/miekg/dns v1.1.55 // 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 v1.0.0 // indirect @@ -354,6 +355,7 @@ require ( 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/pelletier/go-toml v1.9.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect @@ -361,14 +363,13 @@ require ( 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/alertmanager v0.25.1 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.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.44.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.10.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/prometheus v0.46.0 // indirect - github.com/pyroscope-io/client v0.7.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 @@ -379,14 +380,14 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver v2.4.0+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect @@ -433,38 +434,41 @@ require ( go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect go.etcd.io/etcd/client/v3 v3.5.7 // indirect - go.mongodb.org/mongo-driver v1.11.3 // indirect + go.mongodb.org/mongo-driver v1.12.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/sdk v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220817180228-f738f5508c12 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gonum.org/v1/gonum v0.13.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230717213848-3f92550aa753 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/grpc v1.58.3 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -473,23 +477,23 @@ require ( 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.26.2 // indirect + k8s.io/api v0.27.3 // indirect k8s.io/apiextensions-apiserver v0.25.3 // indirect - k8s.io/apimachinery v0.26.2 // indirect + k8s.io/apimachinery v0.27.3 // indirect k8s.io/cli-runtime v0.25.11 // indirect - k8s.io/client-go v0.26.2 // indirect + k8s.io/client-go v0.27.3 // indirect k8s.io/component-base v0.26.2 // indirect - k8s.io/klog/v2 v2.90.1 // indirect - k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d // 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-20230308161112-d77c459e9343 // indirect + k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/controller-runtime v0.13.0 // 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 ) @@ -504,11 +508,11 @@ replace ( github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 // until merged upstream: https://github.com/hashicorp/go-plugin/pull/257 - github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 + github.com/hashicorp/go-plugin => github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 - github.com/sercand/kuberesolver v2.4.0+incompatible => github.com/sercand/kuberesolver/v5 v5.1.0 + github.com/sercand/kuberesolver v2.4.0+incompatible => github.com/sercand/kuberesolver/v5 v5.1.1 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index bd4a8b977c0..3be74077277 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -149,8 +149,8 @@ cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARy cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -668,8 +668,8 @@ github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/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.44.276 h1:ywPlx9C5Yc482dUgAZ9bHpQ6onVvJvYE9FJWsNDCEy0= -github.com/aws/aws-sdk-go v1.44.276/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.302 h1:ST3ko6GrJKn3Xi+nAvxjG3uk/V1pW8KC52WLeIxqqNk= +github.com/aws/aws-sdk-go v1.44.302/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= @@ -678,8 +678,6 @@ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc 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/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.4 h1:wj3BFPrTw8yYgA1OlMqvUk95nc8OMv3cvBSF5erT2W4= -github.com/benbjohnson/clock v1.3.4/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= @@ -923,10 +921,8 @@ github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB 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/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= -github.com/emicklei/go-restful/v3 v3.10.1/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= @@ -938,14 +934,14 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -1073,8 +1069,8 @@ github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9Qy 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.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +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= @@ -1362,10 +1358,10 @@ github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737 h1:o45+fZAYRtTjx+9f github.com/grafana/loki v1.6.2-0.20230403212622-90888a0cc737/go.mod h1:kxNnWCr4EMobhndjy7a2Qpm7jkLPnJW2ariYvY77hLE= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765 h1:VXitROTlmZtLzvokNe8ZbUKpmwldM4Hy1zdNRO32jKU= github.com/grafana/loki/pkg/push v0.0.0-20230127102416-571f88bc5765/go.mod h1:DhJMrd2QInI/1CNtTN43BZuTmkccdizW1jZ+F6aHkhY= -github.com/grafana/pyroscope-go v1.0.2 h1:dEFgO9VbhYTwuwpCC5coTpuW0JjISEWDZtvRAW9v5Tw= -github.com/grafana/pyroscope-go v1.0.2/go.mod h1:bShDKsVZdzxq+Ol6no0JKigU9y5FTWUcFditMXaH09o= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3 h1:eunWpv1B3Z7ZK9o4499EmQGlY+CsDmSZ4FbxjRx37uk= -github.com/grafana/pyroscope-go/godeltaprof v0.1.3/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= +github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= +github.com/grafana/pyroscope-go v1.0.4/go.mod h1:0d7ftwSMBV/Awm7CCiYmHQEG8Y44Ma3YSjt+nWcWztY= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4 h1:mDsJ3ngul7UfrHibGQpV66PbZ3q1T8glz/tK3bQKKEk= +github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko= 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= @@ -1378,8 +1374,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= 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.0-rc.0 h1:mdLirNAJBxnGgyB6pjZLcs6ue/6eZGBui6gXspfq4ks= -github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0/go.mod h1:kdXbOySqcQeTxiqglW7aahTmWZy3Pgi6SYL36yvKeyA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tggROQKKcnh4eItay6z/HbHLqghBxS8g7pyMhmDio= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0/go.mod h1:hKAkSgNkL0FII46ZkJcpVEAai4KV+swlIWCKfekd1pA= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -1388,6 +1384,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= 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= @@ -1399,11 +1397,11 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv 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.21.0 h1:WMR2JiyuaQWRAMFaOGiYfY4Q4HRpyYRe/oYQofjyduM= -github.com/hashicorp/consul/api v1.21.0/go.mod h1:f8zVJwBcLdr1IQnfdfszjUM0xzp31Zl3bpws3pL9uFM= +github.com/hashicorp/consul/api v1.22.0 h1:ydEvDooB/A0c/xpsBd8GSt7P2/zYPBui4KrNip0xGjE= +github.com/hashicorp/consul/api v1.22.0/go.mod h1:zHpYgZ7TeYqS6zaszjwSt128OwESRpnhU9aGa6ue3Eg= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.13.1 h1:EygWVWWMczTzXGpO93awkHFzfUka6hLYJ0qhETd+6lY= -github.com/hashicorp/consul/sdk v0.13.1/go.mod h1:SW/mM4LbKfqmMvcFu8v+eiQQ7oitXEFeiBe9StxERb0= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/cronexpr v1.1.1 h1:NJZDd87hGXjoZBdvyCF9mX4DCq5Wy7+A/w+A7q0wn6c= github.com/hashicorp/cronexpr v1.1.1/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -1673,8 +1671,8 @@ github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs 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.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -1992,8 +1990,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju 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.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= 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= @@ -2181,6 +2179,10 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ 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/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.3.0 h1:mvZaddk4E4kLcXhzb+cxBsMPYp2pHqiQpWYkInsuZPQ= github.com/ovh/go-ovh v1.3.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -2219,8 +2221,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr 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.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= -github.com/pressly/goose/v3 v3.15.0/go.mod h1:LlIo3zGccjb/YUgG+Svdb9Er14vefRdlDI7URCDrwYo= +github.com/pressly/goose/v3 v3.15.1 h1:dKaJ1SdLvS/+HtS8PzFT0KBEtICC1jewLXM+b3emlv8= +github.com/pressly/goose/v3 v3.15.1/go.mod h1:0E3Yg/+EwYzO6Rz2P98MlClFgIcoujbVRs575yi3iIM= github.com/prometheus/alertmanager v0.25.1 h1:LGBNMspOfv8h7brb+LWj2wnwBCg2ZuuKWTh6CAVw2/Y= github.com/prometheus/alertmanager v0.25.1/go.mod h1:MEZ3rFVHqKZsw7IcNS/m4AWZeXThmJhumpiWR4eHU/w= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -2233,15 +2235,15 @@ github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrb github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +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-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/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +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.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= @@ -2268,8 +2270,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2 h1:i5hmbBzR+VeL5pPl1ZncsJ1bpg3SO66bwkE1msJBsMA= github.com/prometheus/prometheus v0.43.1-0.20230327151049-211ae4f1f0a2/go.mod h1:Mm42Acga98xgA+u5yTaC3ki3i0rJEJWFpbdHN7q2trk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -2329,15 +2331,17 @@ github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cj 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/sercand/kuberesolver/v5 v5.1.0 h1:YLqreB1vUFbZHSidcqI5ChMp+RIRmop0brQOeUFWiRw= -github.com/sercand/kuberesolver/v5 v5.1.0/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= +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.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 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.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= 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= @@ -2358,22 +2362,22 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47 h1:vdieOW3CZGdD2R5zvCSMS+0vksyExPN3/Fa1uVfld/A= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230913032705-f924d753cc47/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-env v0.36.0 h1:CFOjs0c0y3lrHi/fl5qseCH9EQa5W/6CFyOvmhe2VnA= -github.com/smartcontractkit/chainlink-env v0.36.0/go.mod h1:NbRExHmJGnKSYXmvNuJx5VErSx26GtE1AEN/CRzYOg8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1 h1:Db333w+fSm2e18LMikcIQHIZqgxZruW9uCUGJLUC9mI= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230926113942-a871b2976dc1/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918/go.mod h1:/yp/sqD8Iz5GU5fcercjrw0ivJF7HDcupYg+Gjr7EPg= -github.com/smartcontractkit/chainlink-testing-framework v1.17.0 h1:JcJwfawW7jfLBG+By5hGTVcNgKQ7bJCqvN9TEF3qBis= -github.com/smartcontractkit/chainlink-testing-framework v1.17.0/go.mod h1:Ry6fRPr8TwrIsYVNEF1pguAgzE3QW1s54tbLWnFtfI4= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kNwgFlDmbE/n0gTSRMt9GBDfsfGrs4X9b9arPZtFI= -github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= +github.com/smartcontractkit/chainlink-env v0.38.3 h1:ZtOnwkG622R0VCTxL5V09AnT/QXhlFwkGTjd0Lsfpfg= +github.com/smartcontractkit/chainlink-env v0.38.3/go.mod h1:7z4sw/hN8TxioQCLwFqQdhK3vaOV0a22Qe99z4bRUcg= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9 h1:fFD5SgSJtnXvkGLK3CExNKpUIz4sGrNNkKv3Ljw63Hk= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231020230319-2ede955d1dc9/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb/go.mod h1:/30flFG4L/iCYAFeA3DUzR0xuHSxAMONiWTzyzvsNwo= +github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36 h1:ow84QG8vEHMvfjGg0RF8HNYh80WcHci6PIenXyY6K8Y= +github.com/smartcontractkit/chainlink-testing-framework v1.17.12-0.20231018101901-23824db88d36/go.mod h1:RWlmjwnjIGbQAnRfKwe02Ife82nNI3rZmdI0zgkfbyk= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= +github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= -github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545 h1:qOsw2ETQD/Sb/W2xuYn2KPWjvvsWA0C+l19rWFq8iNg= +github.com/smartcontractkit/libocr v0.0.0-20231020123319-d255366a6545/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= @@ -2543,8 +2547,10 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY 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/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= 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/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= 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= @@ -2599,8 +2605,8 @@ go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/ 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.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= -go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= +go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= 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= @@ -2611,21 +2617,27 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 h1:pginetY7+onl4qN1vl0xW/V/v6OBZ0vVdH+esuJgvmM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0/go.mod h1:XiYsayHc36K3EByOO6nbAXnAWbrUxdjUROCEeeROOH8= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -2657,8 +2669,8 @@ 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/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +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/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= @@ -2703,8 +2715,8 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2765,8 +2777,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2852,8 +2864,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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= @@ -2902,8 +2914,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -3032,8 +3044,10 @@ golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.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 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= 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 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= @@ -3044,8 +3058,8 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= 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= @@ -3061,8 +3075,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.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.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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= @@ -3154,8 +3168,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= @@ -3430,8 +3444,8 @@ google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsA google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -3517,22 +3531,22 @@ k8s.io/api v0.25.11 h1:4mjYDfE3yp22jrytjH0knwgzjXKkxHX4D01ZCAazvZM= k8s.io/api v0.25.11/go.mod h1:bK4UvD4bthtutNlvensrfBX21PRQ/vs2cIYggHkOOAo= 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.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= -k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +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.11 h1:DJQ141UsbNRI6wYSlcYLP5J5BW5Wq7Bgm42Ztq2SW70= k8s.io/client-go v0.25.11/go.mod h1:41Xs7p1SfhoReUnmjjYCfCNWFiq4xSkexwJfbxF2F7A= 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.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +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-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= 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-20230308161112-d77c459e9343 h1:m7tbIjXGcGIAtpmQr7/NAi7RsWoW3E7Zcm4jI1HicTc= -k8s.io/utils v0.0.0-20230308161112-d77c459e9343/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc= +k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -3583,7 +3597,7 @@ 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/integration-tests/load/functions/README.md b/integration-tests/load/functions/README.md index 65a87b897ac..bcdbe92d524 100644 --- a/integration-tests/load/functions/README.md +++ b/integration-tests/load/functions/README.md @@ -18,7 +18,7 @@ All tests are split by network and in 3 groups: - Secrets decoding payload only - Realistic payload with args/http/secrets -Load test client is [here](../../../contracts/src/v0.8/functions/tests/v1_0_0/testhelpers/FunctionsLoadTestClient.sol) +Load test client is [here](../../../contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsLoadTestClient.sol) Load is controlled with 2 params: - RPS diff --git a/integration-tests/load/vrfv2/cmd/dashboard.go b/integration-tests/load/vrfv2/cmd/dashboard.go index f7e29bd7d75..3035da0422f 100644 --- a/integration-tests/load/vrfv2/cmd/dashboard.go +++ b/integration-tests/load/vrfv2/cmd/dashboard.go @@ -8,10 +8,11 @@ import ( "github.com/K-Phoen/grabana/timeseries" "github.com/K-Phoen/grabana/timeseries/axis" "github.com/smartcontractkit/wasp" + "os" ) func main() { - lokiDS := "grafanacloud-logs" + lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ dashboard.Row("LoadContractMetrics", diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index 97a455dc714..a9fb80a72ad 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -1,10 +1,11 @@ package loadvrfv2 import ( + "testing" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" - "testing" ) func TestVRFV2Load(t *testing.T) { @@ -31,7 +32,7 @@ func TestVRFV2Load(t *testing.T) { T: t, LoadType: wasp.VU, GenName: "vu", - VU: NewJobVolumeVU(cfg.SoakVolume.Pace.Duration(), 1, env.GetAPIs(), env.EVMClient, vrfv2Contracts), + VU: NewJobVolumeVU(cfg.SoakVolume.Pace.Duration(), 1, env.ClCluster.NodeAPIs(), env.EVMClient, vrfv2Contracts), Labels: labels, LokiConfig: wasp.NewEnvLokiConfig(), } diff --git a/integration-tests/load/vrfv2plus/README.md b/integration-tests/load/vrfv2plus/README.md new file mode 100644 index 00000000000..1013a3f4c16 --- /dev/null +++ b/integration-tests/load/vrfv2plus/README.md @@ -0,0 +1,22 @@ +### VRFv2Plus Load tests + +## Usage +``` +export LOKI_TOKEN=... +export LOKI_URL=... + +go test -v -run TestVRFV2PlusLoad/vrfv2plus_soak_test +``` + +### Dashboards + +Deploying dashboard: +``` +export GRAFANA_URL=... +export GRAFANA_TOKEN=... +export DATA_SOURCE_NAME=grafanacloud-logs +export DASHBOARD_FOLDER=LoadTests +export DASHBOARD_NAME=${JobTypeName, for example WaspVRFv2Plus} + +go run dashboard.go +``` \ No newline at end of file diff --git a/integration-tests/load/vrfv2plus/cmd/dashboard.go b/integration-tests/load/vrfv2plus/cmd/dashboard.go new file mode 100644 index 00000000000..9a0ba682a18 --- /dev/null +++ b/integration-tests/load/vrfv2plus/cmd/dashboard.go @@ -0,0 +1,99 @@ +package main + +import ( + "github.com/K-Phoen/grabana/dashboard" + "github.com/K-Phoen/grabana/logs" + "github.com/K-Phoen/grabana/row" + "github.com/K-Phoen/grabana/target/prometheus" + "github.com/K-Phoen/grabana/timeseries" + "github.com/K-Phoen/grabana/timeseries/axis" + "github.com/smartcontractkit/wasp" + "os" +) + +func main() { + lokiDS := os.Getenv("DATA_SOURCE_NAME") + d, err := wasp.NewDashboard(nil, + []dashboard.Option{ + dashboard.Row("LoadContractMetrics", + row.WithTimeSeries( + "RequestCount + FulfilmentCount", + timeseries.Span(12), + timeseries.Height("300px"), + timeseries.DataSource(lokiDS), + timeseries.Axis( + axis.Unit("Requests"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap RequestCount [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} requests"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap FulfilmentCount [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} fulfillments"), + ), + ), + row.WithTimeSeries( + "Fulfillment time (blocks)", + timeseries.Span(12), + timeseries.Height("300px"), + timeseries.DataSource(lokiDS), + timeseries.Axis( + axis.Unit("Blocks"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap AverageFulfillmentInMillions [$__interval]) by (node_id, go_test_name, gen_name) / 1e6 + `, prometheus.Legend("{{go_test_name}} avg"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap SlowestFulfillment [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} slowest"), + ), + timeseries.WithPrometheusTarget( + ` + last_over_time({type="vrfv2plus_contracts_load_summary", go_test_name=~"${go_test_name:pipe}", branch=~"${branch:pipe}", commit=~"${commit:pipe}", gen_name=~"${gen_name:pipe}"} + | json + | unwrap FastestFulfillment [$__interval]) by (node_id, go_test_name, gen_name) + `, prometheus.Legend("{{go_test_name}} fastest"), + ), + ), + ), + dashboard.Row("CL nodes logs", + row.Collapse(), + row.WithLogs( + "CL nodes logs", + logs.DataSource(lokiDS), + logs.Span(12), + logs.Height("300px"), + logs.Transparent(), + logs.WithLokiTarget(` + {type="log_watch"} + `), + )), + }, + ) + if err != nil { + panic(err) + } + // set env vars + //export GRAFANA_URL=... + //export GRAFANA_TOKEN=... + //export DATA_SOURCE_NAME=Loki + //export DASHBOARD_FOLDER=LoadTests + //export DASHBOARD_NAME=Waspvrfv2plus + if _, err := d.Deploy(); err != nil { + panic(err) + } +} diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go new file mode 100644 index 00000000000..5f3babfeab0 --- /dev/null +++ b/integration-tests/load/vrfv2plus/config.go @@ -0,0 +1,127 @@ +package loadvrfv2plus + +import ( + "encoding/base64" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + "os" +) + +const ( + DefaultConfigFilename = "config.toml" + + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" + ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" +) + +type PerformanceConfig struct { + Soak *Soak `toml:"Soak"` + Load *Load `toml:"Load"` + Stress *Stress `toml:"Stress"` + Spike *Spike `toml:"Spike"` + + Common *Common `toml:"Common"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnvConfig"` + NewEnvConfig *NewEnvConfig `toml:"NewEnvConfig"` +} + +type ExistingEnvConfig struct { + CoordinatorAddress string `toml:"coordinator_address"` + ConsumerAddress string `toml:"consumer_address"` + SubID string `toml:"sub_id"` + KeyHash string `toml:"key_hash"` +} + +type NewEnvConfig struct { + Funding + NumberOfSubToCreate int `toml:"number_of_sub_to_create"` +} + +type Common struct { + MinimumConfirmations uint16 `toml:"minimum_confirmations"` +} + +type Funding struct { + NodeFunds float64 `toml:"node_funds"` + SubFundsLink int64 `toml:"sub_funds_link"` + SubFundsNative int64 `toml:"sub_funds_native"` +} + +type Soak struct { + PerformanceTestConfig +} + +type Load struct { + PerformanceTestConfig +} + +type Stress struct { + PerformanceTestConfig +} + +type Spike struct { + PerformanceTestConfig +} + +type PerformanceTestConfig struct { + RPS int64 `toml:"rps"` + //Duration *models.Duration `toml:"duration"` + RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` + RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` + RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` +} + +func ReadConfig() (*PerformanceConfig, error) { + var cfg *PerformanceConfig + rawConfig := os.Getenv("CONFIG") + var d []byte + var err error + if rawConfig == "" { + d, err = os.ReadFile(DefaultConfigFilename) + if err != nil { + return nil, errors.Wrap(err, ErrReadPerfConfig) + } + } else { + d, err = base64.StdEncoding.DecodeString(rawConfig) + } + err = toml.Unmarshal(d, &cfg) + if err != nil { + return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) + } + + if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { + return nil, errors.Wrap(err, ErrDeviationShouldBeLessThanOriginal) + } + + log.Debug().Interface("Config", cfg).Msg("Parsed config") + return cfg, nil +} + +func SetPerformanceTestConfig(vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, cfg *PerformanceConfig) { + switch os.Getenv("TEST_TYPE") { + case "Soak": + vrfv2PlusConfig.RPS = cfg.Soak.RPS + vrfv2PlusConfig.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() + vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest + vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation + case "Load": + vrfv2PlusConfig.RPS = cfg.Load.RPS + vrfv2PlusConfig.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() + vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest + vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation + case "Stress": + vrfv2PlusConfig.RPS = cfg.Stress.RPS + vrfv2PlusConfig.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() + vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest + vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation + case "Spike": + vrfv2PlusConfig.RPS = cfg.Spike.RPS + vrfv2PlusConfig.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() + vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest + vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Spike.RandomnessRequestCountPerRequestDeviation + } +} diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml new file mode 100644 index 00000000000..1208423dc0d --- /dev/null +++ b/integration-tests/load/vrfv2plus/config.toml @@ -0,0 +1,44 @@ + +[Common] +minimum_confirmations = 3 + +[NewEnvConfig] +sub_funds_link = 1000 +sub_funds_native = 1000 +node_funds = 10 +number_of_sub_to_create = 10 + +[ExistingEnvConfig] +coordinator_address = "0x4931Ce2e341398c8eD8A5D0F6ADb920476D6DaBb" +consumer_address = "0x087F232165D9bA1A602f148025e5D0666953F64a" +sub_id = "52116875585187328970776211988181422347535732407068188096422095950800466618218" +key_hash = "0x4c422465ed6a06cfc84575a5437fef7b9dc6263133f648afbe6ae7b2c694d3b3" + + +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds +[Soak] +rate_limit_unit_duration = "6s" +rps = 1 +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting + +# approx 60 RPM - 1 tx request with 4 rand requests in each tx every 3 seconds +[Load] +rate_limit_unit_duration = "3s" +rps = 1 +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting + +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +[Stress] +rate_limit_unit_duration = "0" +rps = 3 +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting + +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +[Spike] +rate_limit_unit_duration = "1m" +rps = 1 +randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go new file mode 100644 index 00000000000..c9947fa32f5 --- /dev/null +++ b/integration-tests/load/vrfv2plus/gun.go @@ -0,0 +1,77 @@ +package loadvrfv2plus + +import ( + "github.com/rs/zerolog" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/wasp" + "math/big" + "math/rand" +) + +/* SingleHashGun is a gun that constantly requests randomness for one feed */ + +type SingleHashGun struct { + contracts *vrfv2plus.VRFV2_5Contracts + keyHash [32]byte + subIDs []*big.Int + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig + logger zerolog.Logger +} + +func NewSingleHashGun( + contracts *vrfv2plus.VRFV2_5Contracts, + keyHash [32]byte, + subIDs []*big.Int, + vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, + logger zerolog.Logger, +) *SingleHashGun { + return &SingleHashGun{ + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + vrfv2PlusConfig: vrfv2PlusConfig, + logger: logger, + } +} + +// Call implements example gun call, assertions on response bodies should be done here +func (m *SingleHashGun) Call(l *wasp.Generator) *wasp.CallResult { + //todo - should work with multiple consumers and consumers having different keyhashes and wallets + + //randomly increase/decrease randomness request count per TX + randomnessRequestCountPerRequest := deviateValue(m.vrfv2PlusConfig.RandomnessRequestCountPerRequest, m.vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation) + _, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + //the same consumer is used for all requests and in all subs + m.contracts.LoadTestConsumers[0], + m.contracts.Coordinator, + &vrfv2plus.VRFV2PlusData{VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{KeyHash: m.keyHash}}, + //randomly pick a subID from pool of subIDs + m.subIDs[randInRange(0, len(m.subIDs)-1)], + //randomly pick payment type + randBool(), + randomnessRequestCountPerRequest, + m.vrfv2PlusConfig, + m.logger, + ) + if err != nil { + return &wasp.CallResult{Error: err.Error(), Failed: true} + } + return &wasp.CallResult{} +} + +func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { + if randBool() && requestCountPerTX > deviation { + requestCountPerTX -= uint16(randInRange(0, int(deviation))) + } else { + requestCountPerTX += uint16(randInRange(0, int(deviation))) + } + return requestCountPerTX +} + +func randBool() bool { + return rand.Intn(2) == 1 +} +func randInRange(min int, max int) int { + return rand.Intn(max-min+1) + min +} diff --git a/integration-tests/load/vrfv2plus/onchain_monitoring.go b/integration-tests/load/vrfv2plus/onchain_monitoring.go new file mode 100644 index 00000000000..0ae27fe6be0 --- /dev/null +++ b/integration-tests/load/vrfv2plus/onchain_monitoring.go @@ -0,0 +1,50 @@ +package loadvrfv2plus + +import ( + "context" + "github.com/rs/zerolog/log" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/wasp" + "testing" + "time" +) + +/* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ + +const ( + LokiTypeLabel = "vrfv2plus_contracts_load_summary" + ErrMetrics = "failed to get VRFv2Plus load test metrics" + ErrLokiClient = "failed to create Loki client for monitoring" + ErrLokiPush = "failed to push monitoring metrics to Loki" +) + +func MonitorLoadStats(lc *wasp.LokiClient, vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, labels map[string]string) { + go func() { + for { + time.Sleep(1 * time.Second) + SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, labels) + } + }() +} + +func UpdateLabels(labels map[string]string, t *testing.T) map[string]string { + updatedLabels := make(map[string]string) + for k, v := range labels { + updatedLabels[k] = v + } + updatedLabels["type"] = LokiTypeLabel + updatedLabels["go_test_name"] = t.Name() + updatedLabels["gen_name"] = "performance" + return updatedLabels +} + +func SendLoadTestMetricsToLoki(vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts, lc *wasp.LokiClient, updatedLabels map[string]string) { + //todo - should work with multiple consumers and consumers having different keyhashes and wallets + metrics, err := vrfv2PlusContracts.LoadTestConsumers[0].GetLoadTestMetrics(context.Background()) + if err != nil { + log.Error().Err(err).Msg(ErrMetrics) + } + if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), metrics); err != nil { + log.Error().Err(err).Msg(ErrLokiPush) + } +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go new file mode 100644 index 00000000000..5c3ea6e8c6d --- /dev/null +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -0,0 +1,188 @@ +package loadvrfv2plus + +import ( + "context" + "github.com/ethereum/go-ethereum/common" + "github.com/kelseyhightower/envconfig" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/wasp" + "github.com/stretchr/testify/require" + "math/big" + "os" + "sync" + "testing" + "time" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" +) + +func TestVRFV2PlusLoad(t *testing.T) { + cfg, err := ReadConfig() + require.NoError(t, err) + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) + + SetPerformanceTestConfig(&vrfv2PlusConfig, cfg) + + l := logging.GetTestLogger(t) + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2PlusConfig.MinimumConfirmations = cfg.Common.MinimumConfirmations + + l.Info(). + Str("Test Type", os.Getenv("TEST_TYPE")). + Str("Test Duration", vrfv2PlusConfig.TestDuration.Truncate(time.Second).String()). + Int64("RPS", vrfv2PlusConfig.RPS). + Str("RateLimitUnitDuration", vrfv2PlusConfig.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", vrfv2PlusConfig.UseExistingEnv). + Msg("Performance Test Configuration") + + var env *test_env.CLClusterTestEnv + var vrfv2PlusContracts *vrfv2plus.VRFV2_5Contracts + var vrfv2PlusData *vrfv2plus.VRFV2PlusData + var subIDs []*big.Int + + if vrfv2PlusConfig.UseExistingEnv { + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2PlusConfig.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress + vrfv2PlusConfig.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2PlusConfig.SubID = cfg.ExistingEnvConfig.SubID + vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash + + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithoutCleanup(). + Build() + + require.NoError(t, err, "error creating test env") + + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(vrfv2PlusConfig.CoordinatorAddress) + require.NoError(t, err) + + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) + require.NoError(t, err) + + vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ + Coordinator: coordinator, + LoadTestConsumers: []contracts.VRFv2PlusLoadTestConsumer{consumer}, + BHS: nil, + } + var ok bool + subID, ok := new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) + require.True(t, ok) + + vrfv2PlusData = &vrfv2plus.VRFV2PlusData{ + VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ + VRFKey: nil, + EncodedProvingKey: [2]*big.Int{}, + KeyHash: common.HexToHash(vrfv2PlusConfig.KeyHash), + }, + VRFJob: nil, + PrimaryEthAddress: "", + ChainID: nil, + } + subIDs = append(subIDs, subID) + } else { + //todo: temporary solution with envconfig and toml config until VRF-662 is implemented + vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeFunds + vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink + vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative + numberOfSubToCreate := cfg.NewEnvConfig.NumberOfSubToCreate + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithCLNodes(1). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). + WithLogWatcher(). + Build() + + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "error deploying LINK contract") + + vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, numberOfSubToCreate) + require.NoError(t, err, "error setting up VRF v2_5 env") + } + + l.Debug().Int("Number of Subs", len(subIDs)).Msg("Subs Involved in Load Test") + for _, subID := range subIDs { + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information for subscription %s", subID.String()) + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) + } + + labels := map[string]string{ + "branch": "vrfv2Plus_healthcheck", + "commit": "vrfv2Plus_healthcheck", + } + + lokiConfig := wasp.NewEnvLokiConfig() + lc, err := wasp.NewLokiClient(lokiConfig) + if err != nil { + l.Error().Err(err).Msg(ErrLokiClient) + return + } + + singleFeedConfig := &wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "gun", + RateLimitUnitDuration: vrfv2PlusConfig.RateLimitUnitDuration, + Gun: NewSingleHashGun( + vrfv2PlusContracts, + vrfv2PlusData.KeyHash, + subIDs, + &vrfv2PlusConfig, + l, + ), + Labels: labels, + LokiConfig: lokiConfig, + CallTimeout: 2 * time.Minute, + } + require.Len(t, vrfv2PlusContracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") + consumer := vrfv2PlusContracts.LoadTestConsumers[0] + err = consumer.ResetMetrics() + require.NoError(t, err) + updatedLabels := UpdateLabels(labels, t) + MonitorLoadStats(lc, vrfv2PlusContracts, updatedLabels) + + // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? + t.Run("vrfv2plus soak test", func(t *testing.T) { + + singleFeedConfig.Schedule = wasp.Plain( + vrfv2PlusConfig.RPS, + vrfv2PlusConfig.TestDuration, + ) + _, err = wasp.NewProfile(). + Add(wasp.NewGenerator(singleFeedConfig)). + Run(true) + require.NoError(t, err) + + var wg sync.WaitGroup + + wg.Add(1) + requestCount, fulfilmentCount, err := vrfv2plus.WaitForRequestCountEqualToFulfilmentCount(consumer, 30*time.Second, &wg) + l.Info(). + Interface("Request Count", requestCount). + Interface("Fulfilment Count", fulfilmentCount). + Msg("Final Request/Fulfilment Stats") + require.NoError(t, err) + wg.Wait() + //send final results + SendLoadTestMetricsToLoki(vrfv2PlusContracts, lc, updatedLabels) + }) + +} diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index d1d79de5eed..bf97f43d058 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -34,6 +34,6 @@ func TestVersionUpgrade(t *testing.T) { // MigrateOnStartup = true // // by default - err = env.CLNodes[0].Restart(env.CLNodes[0].NodeConfig) + err = env.ClCluster.Nodes[0].Restart(env.ClCluster.Nodes[0].NodeConfig) require.NoError(t, err) } diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go index c66a1803564..959cb0fa3e1 100644 --- a/integration-tests/performance/cron_test.go +++ b/integration-tests/performance/cron_test.go @@ -120,19 +120,21 @@ func setupCronTest(t *testing.T) (testEnvironment *environment.Environment) { } baseTOML := `[WebServer] HTTPWriteTimout = '300s'` - cd, err := chainlink.NewDeployment(1, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, network), + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 1, + "toml": client.AddNetworksConfig(baseTOML, network), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, + NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), + Test: t, + PreventPodEviction: true, }). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error launching test environment") return testEnvironment } diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go index 98c03c2bb96..4ff2b856195 100644 --- a/integration-tests/performance/directrequest_test.go +++ b/integration-tests/performance/directrequest_test.go @@ -140,19 +140,21 @@ func setupDirectRequestTest(t *testing.T) (testEnvironment *environment.Environm } baseTOML := `[WebServer] HTTPWriteTimout = '300s'` - cd, err := chainlink.NewDeployment(1, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, network), + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 1, + "toml": client.AddNetworksConfig(baseTOML, network), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, + NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), + Test: t, + PreventPodEviction: true, }). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error launching test environment") return testEnvironment } diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go index 2c33096a356..3f9db27c106 100644 --- a/integration-tests/performance/flux_test.go +++ b/integration-tests/performance/flux_test.go @@ -187,19 +187,21 @@ HTTPWriteTimout = '300s' [OCR] Enabled = true` - cd, err := chainlink.NewDeployment(3, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, testNetwork), + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 3, + "toml": client.AddNetworksConfig(baseTOML, testNetwork), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-flux-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, + NamespacePrefix: fmt.Sprintf("performance-flux-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), + Test: t, + PreventPodEviction: true, }). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConf). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error running test environment") return testEnvironment, testNetwork } diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go index 7ab0f53d0d0..08ea95b4340 100644 --- a/integration-tests/performance/keeper_test.go +++ b/integration-tests/performance/keeper_test.go @@ -153,21 +153,23 @@ TurnLookBack = 0 SyncInterval = '5s' PerformGasOverhead = 150_000` networkName := strings.ReplaceAll(strings.ToLower(network.Name), " ", "-") - cd, err := chainlink.NewDeployment(5, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, network), + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 5, + "toml": client.AddNetworksConfig(baseTOML, network), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment := environment.New( &environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-keeper-%s-%s", testName, networkName), - Test: t, + NamespacePrefix: fmt.Sprintf("performance-keeper-%s-%s", testName, networkName), + Test: t, + PreventPodEviction: true, }, ). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error deploying test environment") if testEnvironment.WillUseRemoteRunner() { return testEnvironment, nil, nil, nil, nil diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go index d3d29049653..f468a0e0370 100644 --- a/integration-tests/performance/ocr_test.go +++ b/integration-tests/performance/ocr_test.go @@ -102,24 +102,30 @@ func setupOCRTest(t *testing.T) (testEnvironment *environment.Environment, testN baseTOML := `[OCR] Enabled = true +[P2P] +[P2P.V2] +Enabled = false + [P2P] [P2P.V1] Enabled = true ListenIP = '0.0.0.0' ListenPort = 6690` - cd, err := chainlink.NewDeployment(6, map[string]interface{}{ - "toml": client.AddNetworksConfig(baseTOML, testNetwork), + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 6, + "toml": client.AddNetworksConfig(baseTOML, testNetwork), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-ocr-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, + NamespacePrefix: fmt.Sprintf("performance-ocr-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), + Test: t, + PreventPodEviction: true, }). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error running test environment") return testEnvironment, testNetwork } diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go index af3a3ecba81..510e378eb82 100644 --- a/integration-tests/performance/vrf_test.go +++ b/integration-tests/performance/vrf_test.go @@ -146,17 +146,18 @@ func setupVRFTest(t *testing.T) (testEnvironment *environment.Environment, testN } baseTOML := `[WebServer] HTTPWriteTimout = '300s'` - cd, err := chainlink.NewDeployment(0, map[string]interface{}{ + cd := chainlink.New(0, map[string]interface{}{ "toml": client.AddNetworksConfig(baseTOML, testNetwork), }) - require.NoError(t, err, "Error creating chainlink deployment") + testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, + NamespacePrefix: fmt.Sprintf("smoke-vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), + Test: t, + PreventPodEviction: true, }). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error running test environment") return testEnvironment, testNetwork } diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index ab439e59f29..660d9c48e12 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -36,7 +36,6 @@ Enabled = true [P2P] [P2P.V2] -Enabled = true AnnounceAddresses = ["0.0.0.0:6690"] ListenAddresses = ["0.0.0.0:6690"]` networkTOML = `Enabled = true @@ -77,7 +76,7 @@ LimitDefault = 5_000_000` "networkId": "1337", }, "miner": map[string]interface{}{ - "replicas": "2", + "replicas": 2, }, }, }, @@ -124,134 +123,147 @@ const ( * normal pace after the event. */ func TestAutomationReorg(t *testing.T) { + t.Parallel() l := logging.GetTestLogger(t) - network := networks.SelectedNetwork - - cd, err := chainlink.NewDeployment(numberOfNodes, defaultAutomationSettings) - require.NoError(t, err, "Error creating chainlink deployment") - testEnvironment := environment. - New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("automation-reorg-%d", automationReorgBlocks), - TTL: time.Hour * 1, - Test: t}). - AddHelm(reorg.New(defaultReorgEthereumSettings)). - AddChart(blockscout.New(&blockscout.Props{ - Name: "geth-blockscout", - WsURL: activeEVMNetwork.URL, - HttpURL: activeEVMNetwork.HTTPURLs[0]})). - AddHelmCharts(cd) - err = testEnvironment.Run() - require.NoError(t, err, "Error setting up test environment") - - if testEnvironment.WillUseRemoteRunner() { - return - } - chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - chainClient.ParallelTransactions(true) - - // Register cleanup for any test - t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") - }) - - txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) - require.NoError(t, err, "Error estimating cost for Chainlink Operations") - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) - require.NoError(t, err, "Error funding Chainlink nodes") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Error deploying LINK token") - - registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( - t, - ethereum.RegistryVersion_2_0, - defaultOCRRegistryConfig, - linkToken, - contractDeployer, - chainClient, - ) - - // Fund the registry with LINK - err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(numberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - - actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, ethereum.RegistryVersion_2_0) - nodesWithoutBootstrap := chainlinkNodes[1:] - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, defaultOCRRegistryConfig, registrar.Address(), 30*time.Second) - require.NoError(t, err, "OCR2 config should be built successfully") - err = registry.SetConfig(defaultOCRRegistryConfig, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") - require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") - - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false) - - l.Info().Msg("Waiting for all upkeeps to be performed") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - expect := 5 - l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), - "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) - } - }, "7m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~3m for performing each upkeep 5 times, ~3m buffer - - l.Info().Msg("All upkeeps performed under happy path. Starting reorg") - - rc, err := NewReorgController( - &ReorgConfig{ - FromPodLabel: reorg.TXNodesAppLabel, - ToPodLabel: reorg.MinerNodesAppLabel, - Network: chainClient, - Env: testEnvironment, - BlockConsensusThreshold: 3, - Timeout: 1800 * time.Second, - }, - ) - - require.NoError(t, err, "Error getting reorg controller") - rc.ReOrg(automationReorgBlocks) - rc.WaitReorgStarted() - - l.Info().Msg("Reorg started. Expecting chain to become unstable and upkeeps to still getting performed") - - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 10 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - expect := 10 - l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), - "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) - } - }, "5m", "1s").Should(gomega.Succeed()) - - l.Info().Msg("Upkeep performed during unstable chain, waiting for reorg to finish") - rc.WaitDepthReached() - - l.Info().Msg("Reorg finished, chain should be stable now. Expecting upkeeps to keep getting performed") - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 20 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(context.Background()) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - expect := 20 - l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), - "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) - } - }, "10m", "1s").Should(gomega.Succeed()) + registryVersions := map[string]ethereum.KeeperRegistryVersion{ + "registry_2_0": ethereum.RegistryVersion_2_0, + "registry_2_1_conditional": ethereum.RegistryVersion_2_1, + "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, + } + for name, registryVersion := range registryVersions { + t.Run(name, func(t *testing.T) { + t.Parallel() + network := networks.SelectedNetwork + + defaultAutomationSettings["replicas"] = numberOfNodes + cd := chainlink.New(0, defaultAutomationSettings) + testEnvironment := environment. + New(&environment.Config{ + NamespacePrefix: fmt.Sprintf("automation-reorg-%d", automationReorgBlocks), + TTL: time.Hour * 1, + Test: t}). + AddHelm(reorg.New(defaultReorgEthereumSettings)). + AddChart(blockscout.New(&blockscout.Props{ + Name: "geth-blockscout", + WsURL: activeEVMNetwork.URL, + HttpURL: activeEVMNetwork.HTTPURLs[0]})). + AddHelm(cd) + err := testEnvironment.Run() + require.NoError(t, err, "Error setting up test environment") + + if testEnvironment.WillUseRemoteRunner() { + return + } + + chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) + require.NoError(t, err, "Error connecting to blockchain") + contractDeployer, err := contracts.NewContractDeployer(chainClient, l) + require.NoError(t, err, "Error building contract deployer") + chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) + require.NoError(t, err, "Error connecting to Chainlink nodes") + chainClient.ParallelTransactions(true) + + // Register cleanup for any test + t.Cleanup(func() { + err := actions.TeardownSuite(t, testEnvironment, utils.ProjectRoot, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + require.NoError(t, err, "Error tearing down environment") + }) + + txCost, err := chainClient.EstimateCostForChainlinkOperations(1000) + require.NoError(t, err, "Error estimating cost for Chainlink Operations") + err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, txCost) + require.NoError(t, err, "Error funding Chainlink nodes") + + linkToken, err := contractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Error deploying LINK token") + + registry, registrar := actions.DeployAutoOCRRegistryAndRegistrar( + t, + registryVersion, + defaultOCRRegistryConfig, + linkToken, + contractDeployer, + chainClient, + ) + // Fund the registry with LINK + err = linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(numberOfUpkeeps)))) + require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + + actions.CreateOCRKeeperJobs(t, chainlinkNodes, registry.Address(), network.ChainID, 0, registryVersion) + nodesWithoutBootstrap := chainlinkNodes[1:] + ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, nodesWithoutBootstrap, defaultOCRRegistryConfig, registrar.Address(), 5*time.Second) + require.NoError(t, err, "OCR2 config should be built successfully") + err = registry.SetConfig(defaultOCRRegistryConfig, ocrConfig) + require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(t, chainClient.WaitForEvents(), "Waiting for config to be set") + + // Use the name to determine if this is a log trigger or not + isLogTrigger := name == "registry_2_1_logtrigger" + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, isLogTrigger, false) + + l.Info().Msg("Waiting for all upkeeps to be performed") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they are greater than 5 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 5 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "7m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~3m for performing each upkeep 5 times, ~3m buffer + + l.Info().Msg("All upkeeps performed under happy path. Starting reorg") + + rc, err := NewReorgController( + &ReorgConfig{ + FromPodLabel: reorg.TXNodesAppLabel, + ToPodLabel: reorg.MinerNodesAppLabel, + Network: chainClient, + Env: testEnvironment, + BlockConsensusThreshold: 3, + Timeout: 1800 * time.Second, + }, + ) + + require.NoError(t, err, "Error getting reorg controller") + rc.ReOrg(automationReorgBlocks) + rc.WaitReorgStarted() + + l.Info().Msg("Reorg started. Expecting chain to become unstable and upkeeps to still getting performed") + + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 10 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 10 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "5m", "1s").Should(gomega.Succeed()) + + l.Info().Msg("Upkeep performed during unstable chain, waiting for reorg to finish") + rc.WaitDepthReached() + + l.Info().Msg("Reorg finished, chain should be stable now. Expecting upkeeps to keep getting performed") + gom.Eventually(func(g gomega.Gomega) { + // Check if the upkeeps are performing multiple times by analyzing their counters and checking they reach 20 + for i := 0; i < len(upkeepIDs); i++ { + counter, err := consumers[i].Counter(context.Background()) + require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) + expect := 20 + l.Info().Int64("Upkeeps Performed", counter.Int64()).Int("Upkeep ID", i).Msg("Number of upkeeps performed") + g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), + "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) + } + }, "10m", "1s").Should(gomega.Succeed()) + }) + } } diff --git a/integration-tests/reorg/reorg_confirmer.go b/integration-tests/reorg/reorg_confirmer.go index afdc094b591..6647816c975 100644 --- a/integration-tests/reorg/reorg_confirmer.go +++ b/integration-tests/reorg/reorg_confirmer.go @@ -58,7 +58,7 @@ type ReorgController struct { initConsensusReady chan struct{} reorgStarted chan struct{} depthReached chan struct{} - once *sync.Once + once sync.Once mutex sync.Mutex ctx context.Context cancel context.CancelFunc @@ -82,11 +82,8 @@ func NewReorgController(cfg *ReorgConfig) (*ReorgController, error) { initConsensusReady: make(chan struct{}, 100), reorgStarted: make(chan struct{}, 100), depthReached: make(chan struct{}, 100), - once: &sync.Once{}, - mutex: sync.Mutex{}, ctx: ctx, cancel: ctxCancel, - complete: false, } rc.networkStep.Store(InitConsensus) for _, c := range cfg.Network.GetClients() { diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go index 5666d8c7540..74468b92536 100644 --- a/integration-tests/reorg/reorg_test.go +++ b/integration-tests/reorg/reorg_test.go @@ -125,11 +125,12 @@ func TestDirectRequestReorg(t *testing.T) { time.Sleep(90 * time.Second) activeEVMNetwork = networks.SimulatedEVMNonDev netCfg := fmt.Sprintf(networkDRTOML, EVMFinalityDepth, EVMTrackerHistoryDepth) - chainlinkDeployment, err := chainlink.NewDeployment(1, map[string]interface{}{ - "toml": client.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), + chainlinkDeployment := chainlink.New(0, map[string]interface{}{ + "replicas": 1, + "toml": client.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), }) - require.NoError(t, err, "Error building Chainlink deployment") - err = testEnvironment.AddHelmCharts(chainlinkDeployment).Run() + + err = testEnvironment.AddHelm(chainlinkDeployment).Run() require.NoError(t, err, "Error adding to test environment") chainClient, err := blockchain.NewEVMClient(networkSettings, testEnvironment, l) diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index 3955023685d..cb5c98fde6a 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -21,7 +21,9 @@ exit_code=$? echo "Test exit code: ${exit_code}" -if [ $exit_code -eq 2 ]; then # 2 is the code for an interrupted test, we only want to restart the test when the test is interrupted +# 3 is the code for an interrupted test, we only want to restart the test when the test is interrupted and in a state +# that it can recover from. Otherwise we mark the test as "passed" as far as K8s is concerned so it doesn't restart it. +if [ $exit_code -eq 3 ]; then exit 1 # Exiting with non-zero status to trigger pod restart fi diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index 76ee75b21ba..9b79e1bea40 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -2,13 +2,17 @@ package smoke import ( "context" + "encoding/json" "fmt" "math/big" + "net/http" "os" "strconv" "testing" "time" + "github.com/kelseyhightower/envconfig" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/stretchr/testify/require" @@ -16,7 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils" + + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -25,9 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" - cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -86,9 +92,12 @@ func TestAutomationBasic(t *testing.T) { func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { t.Parallel() registryVersions := map[string]ethereum.KeeperRegistryVersion{ - "registry_2_0": ethereum.RegistryVersion_2_0, - "registry_2_1_conditional": ethereum.RegistryVersion_2_1, - "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, + "registry_2_0": ethereum.RegistryVersion_2_0, + "registry_2_1_conditional": ethereum.RegistryVersion_2_1, + "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, + "registry_2_1_with_mercury_v02": ethereum.RegistryVersion_2_1, + "registry_2_1_with_mercury_v03": ethereum.RegistryVersion_2_1, + "registry_2_1_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_1, } for n, rv := range registryVersions { @@ -105,19 +114,24 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { testName = "basic-upkeep" ) if nodeUpgrade { - upgradeImage, err = utils.GetEnv("UPGRADE_IMAGE") - require.NoError(t, err, "Error getting upgrade image") - upgradeVersion, err = utils.GetEnv("UPGRADE_VERSION") - require.NoError(t, err, "Error getting upgrade version") + upgradeImage = os.Getenv("UPGRADE_IMAGE") + upgradeVersion = os.Getenv("UPGRADE_VERSION") + if len(upgradeImage) == 0 || len(upgradeVersion) == 0 { + t.Fatal("UPGRADE_IMAGE and UPGRADE_VERSION must be set to upgrade nodes") + } testName = "node-upgrade" } + + // Use the name to determine if this is a log trigger or mercury + isLogTrigger := name == "registry_2_1_logtrigger" || name == "registry_2_1_with_logtrigger_and_mercury_v02" + isMercuryV02 := name == "registry_2_1_with_mercury_v02" || name == "registry_2_1_with_logtrigger_and_mercury_v02" + isMercuryV03 := name == "registry_2_1_with_mercury_v03" + isMercury := isMercuryV02 || isMercuryV03 + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupAutomationTestDocker( - t, testName, registryVersion, defaultOCRRegistryConfig, nodeUpgrade, + t, testName, registryVersion, defaultOCRRegistryConfig, nodeUpgrade, isMercuryV02, isMercuryV03, ) - // Use the name to determine if this is a log trigger or not - isLogTrigger := name == "registry_2_1_logtrigger" - consumers, upkeepIDs := actions.DeployConsumers( t, registry, @@ -129,18 +143,31 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, isLogTrigger, + isMercury, ) - l.Info().Msg("Waiting for all upkeeps to be performed") - gom := gomega.NewGomegaWithT(t) - for i := 0; i < len(upkeepIDs); i++ { - err := consumers[i].Start() - if err != nil { - return + if isLogTrigger || isMercuryV02 { + if err := consumers[i].Start(); err != nil { + l.Error().Msg("Error when starting consumer") + return + } + } + + if isMercury { + // Set privilege config to enable mercury + privilegeConfigBytes, _ := json.Marshal(evm21.UpkeepPrivilegeConfig{ + MercuryEnabled: true, + }) + if err := registry.SetUpkeepPrivilegeConfig(upkeepIDs[i], privilegeConfigBytes); err != nil { + l.Error().Msg("Error when setting upkeep privilege config") + return + } } } + l.Info().Msg("Waiting for all upkeeps to be performed") + gom := gomega.NewGomegaWithT(t) startTime := time.Now() // TODO Tune this timeout window after stress testing gom.Eventually(func(g gomega.Gomega) { @@ -161,7 +188,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.CLNodes[i]) + actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, testEnv.ClCluster.Nodes[i]) time.Sleep(time.Second * 10) expect = expect + 5 gom.Eventually(func(g gomega.Gomega) { @@ -215,7 +242,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, + t, "set-trigger-config", ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, false, false, false, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -229,6 +256,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, true, + false, ) // Start log trigger based upkeeps for all consumers @@ -389,10 +417,10 @@ func TestAutomationAddFunds(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "add-funds", registryVersion, defaultOCRRegistryConfig, false, + t, "add-funds", registryVersion, defaultOCRRegistryConfig, false, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false) + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false, false) gom := gomega.NewGomegaWithT(t) // Since the upkeep is currently underfunded, check that it doesn't get executed @@ -440,10 +468,10 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, + t, "pause-unpause", registryVersion, defaultOCRRegistryConfig, false, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { @@ -523,10 +551,10 @@ func TestAutomationRegisterUpkeep(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, + t, "register-upkeep", registryVersion, defaultOCRRegistryConfig, false, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) var initialCounters = make([]*big.Int, len(upkeepIDs)) gom := gomega.NewGomegaWithT(t) @@ -594,10 +622,10 @@ func TestAutomationPauseRegistry(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "pause-registry", registryVersion, defaultOCRRegistryConfig, false, + t, "pause-registry", registryVersion, defaultOCRRegistryConfig, false, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) gom := gomega.NewGomegaWithT(t) // Observe that the upkeeps which are initially registered are performing @@ -652,10 +680,10 @@ func TestAutomationKeeperNodesDown(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, + t, "keeper-nodes-down", registryVersion, defaultOCRRegistryConfig, false, false, false, ) - consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false) + consumers, upkeepIDs := actions.DeployConsumers(t, registry, registrar, linkToken, contractDeployer, chainClient, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false) gom := gomega.NewGomegaWithT(t) nodesWithoutBootstrap := chainlinkNodes[1:] @@ -737,7 +765,7 @@ func TestAutomationPerformSimulation(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "perform-simulation", registryVersion, defaultOCRRegistryConfig, false, + t, "perform-simulation", registryVersion, defaultOCRRegistryConfig, false, false, false, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( @@ -801,7 +829,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, chainlinkNodes, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, + t, "gas-limit", registryVersion, defaultOCRRegistryConfig, false, false, false, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( @@ -880,7 +908,8 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { highCheckGasLimit := automationDefaultRegistryConfig highCheckGasLimit.CheckGasLimit = uint32(5000000) highCheckGasLimit.RegistryVersion = registryVersion - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second) + + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, nodesWithoutBootstrap, highCheckGasLimit, registrar.Address(), 30*time.Second, registry.RegistryOwnerAddress()) require.NoError(t, err, "Error building OCR config") err = registry.SetConfig(highCheckGasLimit, ocrConfig) @@ -914,7 +943,7 @@ func TestUpdateCheckData(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) chainClient, _, contractDeployer, linkToken, registry, registrar, _ := setupAutomationTestDocker( - t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, + t, "update-check-data", registryVersion, defaultOCRRegistryConfig, false, false, false, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( @@ -973,12 +1002,18 @@ func TestUpdateCheckData(t *testing.T) { } } +type TestConfig struct { + ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:"1"` +} + func setupAutomationTestDocker( t *testing.T, testName string, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, statefulDb bool, + isMercuryV02 bool, + isMercuryV03 bool, ) ( blockchain.EVMClient, []*client.ChainlinkClient, @@ -988,6 +1023,8 @@ func setupAutomationTestDocker( contracts.KeeperRegistrar, *test_env.CLClusterTestEnv, ) { + require.False(t, isMercuryV02 && isMercuryV03, "Cannot run test with both Mercury V02 and V03 on") + l := logging.GetTestLogger(t) // Add registry version to config registryConfig.RegistryVersion = registryVersion @@ -1001,28 +1038,77 @@ func setupAutomationTestDocker( clNodeConfig.Keeper.TurnLookBack = it_utils.Ptr[int64](int64(0)) clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = it_utils.Ptr[uint32](uint32(150000)) - clNodeConfig.P2P.V2.Enabled = it_utils.Ptr[bool](true) clNodeConfig.P2P.V2.AnnounceAddresses = &[]string{"0.0.0.0:6690"} clNodeConfig.P2P.V2.ListenAddresses = &[]string{"0.0.0.0:6690"} - // launch the environment - env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). - WithMockServer(1). - WithCLNodes(5). - WithCLNodeConfig(clNodeConfig). - WithFunding(big.NewFloat(.5)). - Build() - require.NoError(t, err, "Error deploying test environment") - env.ParallelTransactions(true) + //launch the environment + var env *test_env.CLClusterTestEnv + var err error + var testConfig TestConfig + err = envconfig.Process("AUTOMATION", &testConfig) + require.NoError(t, err) + l.Debug().Msgf("Funding amount: %f", testConfig.ChainlinkNodeFunding) + clNodesCount := 5 + if isMercuryV02 || isMercuryV03 { + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithMockAdapter(). + WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "Error deploying test environment for Mercury") + env.ParallelTransactions(true) + + secretsConfig := ` + [Mercury.Credentials.cred1] + LegacyURL = '%s' + URL = '%s' + Username = 'node' + Password = 'nodepass'` + secretsConfig = fmt.Sprintf(secretsConfig, env.MockAdapter.InternalEndpoint, env.MockAdapter.InternalEndpoint) + + var httpUrls []string + var wsUrls []string + if network.Simulated { + httpUrls = []string{env.Geth.InternalHttpUrl} + wsUrls = []string{env.Geth.InternalWsUrl} + } else { + httpUrls = network.HTTPURLs + wsUrls = network.URLs + } + + node.SetChainConfig(clNodeConfig, wsUrls, httpUrls, network, false) + + err = env.StartClCluster(clNodeConfig, clNodesCount, secretsConfig) + require.NoError(t, err, "Error starting CL nodes test environment for Mercury") + err = env.FundChainlinkNodes(big.NewFloat(testConfig.ChainlinkNodeFunding)) + require.NoError(t, err, "Error funding CL nodes") + + if isMercuryV02 { + output := `{"chainlinkBlob":"0x0001c38d71fed6c320b90e84b6f559459814d068e2a1700adc931ca9717d4fe70000000000000000000000000000000000000000000000000000000001a80b52b4bf1233f9cb71144a253a1791b202113c4ab4a92fa1b176d684b4959666ff8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004254432d5553442d415242495452554d2d544553544e4554000000000000000000000000000000000000000000000000000000000000000000000000645570be000000000000000000000000000000000000000000000000000002af2b818dc5000000000000000000000000000000000000000000000000000002af2426faf3000000000000000000000000000000000000000000000000000002af32dc209700000000000000000000000000000000000000000000000000000000012130f8df0a9745bb6ad5e2df605e158ba8ad8a33ef8a0acf9851f0f01668a3a3f2b68600000000000000000000000000000000000000000000000000000000012130f60000000000000000000000000000000000000000000000000000000000000002c4a7958dce105089cf5edb68dad7dcfe8618d7784eb397f97d5a5fade78c11a58275aebda478968e545f7e3657aba9dcbe8d44605e4c6fde3e24edd5e22c94270000000000000000000000000000000000000000000000000000000000000002459c12d33986018a8959566d145225f0c4a4e61a9a3f50361ccff397899314f0018162cf10cd89897635a0bb62a822355bd199d09f4abe76e4d05261bb44733d"}` + env.MockAdapter.SetStringValuePath("/client", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + } + if isMercuryV03 { + output := `{"reports":[{"feedID":"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000","validFromTimestamp":0,"observationsTimestamp":0,"fullReport":"0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000000081401000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000289ad8d367000000000000000000000000000000000000000000000000000000289acf0b38000000000000000000000000000000000000000000000000000000289b3da40000000000000000000000000000000000000000000000000000000000018ae7ce74d9fa252a8983976eab600dc7590c778d04813430841bc6e765c34cd81a168d00000000000000000000000000000000000000000000000000000000018ae7cb0000000000000000000000000000000000000000000000000000000064891c98000000000000000000000000000000000000000000000000000000000000000260412b94e525ca6cedc9f544fd86f77606d52fe731a5d069dbe836a8bfc0fb8c911963b0ae7a14971f3b4621bffb802ef0605392b9a6c89c7fab1df8633a5ade00000000000000000000000000000000000000000000000000000000000000024500c2f521f83fba5efc2bf3effaaedde43d0a4adff785c1213b712a3aed0d8157642a84324db0cf9695ebd27708d4608eb0337e0dd87b0e43f0fa70c700d911"}]}` + env.MockAdapter.SetStringValuePath("/api/v1/reports/bulk", []string{http.MethodGet, http.MethodPost}, map[string]string{"Content-Type": "application/json"}, output) + } + } else { + env, err = test_env.NewCLTestEnvBuilder(). + WithTestLogger(t). + WithGeth(). + WithMockAdapter(). + WithCLNodes(clNodesCount). + WithCLNodeConfig(clNodeConfig). + WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "Error deploying test environment") + } - txCost, err := env.EVMClient.EstimateCostForChainlinkOperations(1000) - require.NoError(t, err, "Error estimating cost for Chainlink Operations") - nodeClients := env.GetAPIs() + env.ParallelTransactions(true) + nodeClients := env.ClCluster.NodeAPIs() workerNodes := nodeClients[1:] - err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, txCost) - require.NoError(t, err, "Error funding Chainlink nodes") linkToken, err := env.ContractDeployer.DeployLinkTokenContract() require.NoError(t, err, "Error deploying LINK token") @@ -1042,7 +1128,7 @@ func setupAutomationTestDocker( err = actions.CreateOCRKeeperJobsLocal(l, nodeClients, registry.Address(), network.ChainID, 0, registryVersion) require.NoError(t, err, "Error creating OCR Keeper Jobs") - ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, workerNodes, registryConfig, registrar.Address(), 30*time.Second) + ocrConfig, err := actions.BuildAutoOCR2ConfigVarsLocal(l, workerNodes, registryConfig, registrar.Address(), 30*time.Second, registry.RegistryOwnerAddress()) require.NoError(t, err, "Error building OCR config vars") err = registry.SetConfig(automationDefaultRegistryConfig, ocrConfig) require.NoError(t, err, "Registry config should be set successfully") diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index d5311641ce7..ad6de592ede 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -3,7 +3,7 @@ { "name": "TestAutomationBasic", "label": "ubuntu20.04-32cores-128GB", - "nodes": 3 + "nodes": 6 }, { "name": "TestSetUpkeepTriggerConfig" diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 717ff8db1e9..e9d20f588e2 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -2,6 +2,7 @@ package smoke import ( "fmt" + "net/http" "testing" "github.com/google/uuid" @@ -21,28 +22,24 @@ func TestCronBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(1). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) - err = env.MockServer.Client.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting value path in mockserver shouldn't fail") + err = env.MockAdapter.SetAdapterBasedIntValuePath("/variable", []string{http.MethodGet, http.MethodPost}, 5) + require.NoError(t, err, "Setting value path in mock adapter shouldn't fail") bta := &client.BridgeTypeAttributes{ Name: fmt.Sprintf("variable-%s", uuid.NewString()), - URL: fmt.Sprintf("%s/variable", env.MockServer.InternalEndpoint), + URL: fmt.Sprintf("%s/variable", env.MockAdapter.InternalEndpoint), RequestData: "{}", } - err = env.CLNodes[0].API.MustCreateBridge(bta) + err = env.ClCluster.Nodes[0].API.MustCreateBridge(bta) require.NoError(t, err, "Creating bridge in chainlink node shouldn't fail") - job, err := env.CLNodes[0].API.MustCreateJob(&client.CronJobSpec{ + job, err := env.ClCluster.Nodes[0].API.MustCreateJob(&client.CronJobSpec{ Schedule: "CRON_TZ=UTC * * * * * *", ObservationSource: client.ObservationSourceSpecBridge(bta), }) @@ -50,7 +47,10 @@ func TestCronBasic(t *testing.T) { gom := gomega.NewGomegaWithT(t) gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := env.CLNodes[0].API.MustReadRunsByJob(job.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) + if err != nil { + l.Info().Err(err).Msg("error while waiting for job runs") + } g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Reading Job run data shouldn't fail") g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 5), "Expected number of job runs to be greater than 5, but got %d", len(jobRuns.Data)) @@ -58,5 +58,5 @@ func TestCronBasic(t *testing.T) { for _, jr := range jobRuns.Data { g.Expect(jr.Attributes.Errors).Should(gomega.Equal([]interface{}{nil}), "Job run %s shouldn't have errors", jr.ID) } - }, "20m", "3s").Should(gomega.Succeed()) + }, "2m", "3s").Should(gomega.Succeed()) } diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index ed907e9e460..8c2b3638bff 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "net/http" "strings" "testing" "time" @@ -27,24 +28,20 @@ func TestFluxBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(3). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) - nodeAddresses, err := env.ChainlinkNodeAddresses() + nodeAddresses, err := env.ClCluster.NodeAddresses() require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") env.EVMClient.ParallelTransactions(true) adapterUUID := uuid.NewString() adapterPath := fmt.Sprintf("/variable-%s", adapterUUID) - err = env.MockServer.Client.SetValuePath(adapterPath, 1e5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") + err = env.MockAdapter.SetAdapterBasedIntValuePath(adapterPath, []string{http.MethodPost}, 1e5) + require.NoError(t, err, "Setting mock adapter value path shouldn't fail") lt, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") @@ -81,13 +78,13 @@ func TestFluxBasic(t *testing.T) { require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") - adapterFullURL := fmt.Sprintf("%s%s", env.MockServer.Client.Config.ClusterURL, adapterPath) + adapterFullURL := fmt.Sprintf("%s%s", env.MockAdapter.InternalEndpoint, adapterPath) l.Info().Str("AdapterFullURL", adapterFullURL).Send() bta := &client.BridgeTypeAttributes{ Name: fmt.Sprintf("variable-%s", adapterUUID), URL: adapterFullURL, } - for i, n := range env.CLNodes { + for i, n := range env.ClCluster.Nodes { err = n.API.MustCreateBridge(bta) require.NoError(t, err, "Creating bridge shouldn't fail for node %d", i+1) @@ -126,7 +123,7 @@ func TestFluxBasic(t *testing.T) { fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) env.EVMClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = env.MockServer.Client.SetValuePath(adapterPath, 1e10) + err = env.MockAdapter.SetAdapterBasedIntValuePath(adapterPath, []string{http.MethodPost}, 1e10) require.NoError(t, err, "Setting value path in mock server shouldn't fail") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index f0d20e5245c..727b83a601a 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -21,21 +21,17 @@ func TestForwarderOCRBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithForwarders(). WithCLNodes(6). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) - nodeClients := env.GetAPIs() + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] workerNodeAddresses, err := actions.ChainlinkNodeAddressesLocal(workerNodes) @@ -69,19 +65,18 @@ func TestForwarderOCRBasic(t *testing.T) { ) require.NoError(t, err, "Error deploying OCR contracts") - err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) require.NoError(t, err, "failed to setup forwarder jobs") err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - //time.Sleep(999 * time.Second) answer, err := ocrInstances[0].GetLatestAnswer(context.Background()) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) - err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockServer.Client) + err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 48d1d20b4dc..baa5a781f6b 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "net/http" "testing" "time" @@ -25,7 +26,7 @@ func TestForwarderOCR2Basic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), node.WithP2Pv2(), @@ -33,17 +34,13 @@ func TestForwarderOCR2Basic(t *testing.T) { WithForwarders(). WithCLNodes(6). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) - nodeClients := env.GetAPIs() + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] workerNodeAddresses, err := actions.ChainlinkNodeAddressesLocal(workerNodes) @@ -80,7 +77,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockServer.Client, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true) + err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true) require.NoError(t, err, "Error creating OCRv2 jobs with forwarders") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -101,7 +98,7 @@ func TestForwarderOCR2Basic(t *testing.T) { for i := 2; i <= 3; i++ { ocrRoundVal := (5 + i) % 10 - err = env.MockServer.Client.SetValuePath("ocr2", ocrRoundVal) + err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, ocrRoundVal) require.NoError(t, err) err = actions.StartNewOCR2Round(int64(i), ocrInstances, env.EVMClient, time.Minute*10, l) require.NoError(t, err) diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index 0e4cb7ce041..d42944fd558 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -1098,29 +1098,23 @@ func setupKeeperTest(t *testing.T) ( contracts.LinkToken, *test_env.CLClusterTestEnv, ) { - clNodeConfig := node.NewConfig(node.NewBaseConfig()) + clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv1()) turnLookBack := int64(0) syncInterval := models.MustMakeDuration(5 * time.Second) performGasOverhead := uint32(150000) clNodeConfig.Keeper.TurnLookBack = &turnLookBack clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead - l := logging.GetTestLogger(t) env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). WithCLNodes(5). WithCLNodeConfig(clNodeConfig). WithFunding(big.NewFloat(.5)). + WithStandardCleanup(). Build() require.NoError(t, err, "Error deploying test environment") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) @@ -1130,5 +1124,5 @@ func setupKeeperTest(t *testing.T) ( err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - return env.EVMClient, env.GetAPIs(), env.ContractDeployer, linkTokenContract, env + return env.EVMClient, env.ClCluster.NodeAPIs(), env.ContractDeployer, linkTokenContract, env } diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index a1ad9fa5296..d82d84a2072 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "net/http" "strings" "testing" "time" @@ -34,24 +35,21 @@ func TestOCRv2Basic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), node.WithP2Pv2(), + node.WithTracing(), )). WithCLNodes(6). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) - nodeClients := env.GetAPIs() + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] linkToken, err := env.ContractDeployer.DeployLinkTokenContract() @@ -74,7 +72,7 @@ func TestOCRv2Basic(t *testing.T) { aggregatorContracts, err := actions.DeployOCRv2Contracts(1, linkToken, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockServer.Client, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -92,7 +90,7 @@ func TestOCRv2Basic(t *testing.T) { roundData.Answer.Int64(), ) - err = env.MockServer.Client.SetValuePath("ocr2", 10) + err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) err = actions.StartNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) require.NoError(t, err) @@ -126,10 +124,10 @@ func setupOCR2Test(t *testing.T, forwardersEnabled bool) ( toml = client.AddNetworksConfig(config.BaseOCR2Config, testNetwork) } - chainlinkChart, err := chainlink.NewDeployment(6, map[string]interface{}{ - "toml": toml, + chainlinkChart := chainlink.New(0, map[string]interface{}{ + "replicas": 6, + "toml": toml, }) - require.NoError(t, err, "Error creating chainlink deployment") testEnvironment = environment.New(&environment.Config{ NamespacePrefix: fmt.Sprintf("smoke-ocr2-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), @@ -138,8 +136,8 @@ func setupOCR2Test(t *testing.T, forwardersEnabled bool) ( AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). AddHelm(evmConfig). - AddHelmCharts(chainlinkChart) - err = testEnvironment.Run() + AddHelm(chainlinkChart) + err := testEnvironment.Run() require.NoError(t, err, "Error running test environment") return testEnvironment, testNetwork } diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index c9f689ca7ae..81488639187 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -159,21 +159,22 @@ func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environ }) } - cd, err := chainlink.NewDeployment(6, map[string]interface{}{ + cd := chainlink.New(0, map[string]interface{}{ + "replicas": 6, "toml": client.AddNetworkDetailedConfig( config.BaseOCR2Config, config.DefaultOCR2VRFNetworkDetailTomlConfig, testNetwork, ), }) - require.NoError(t, err, "Error creating Chainlink deployment") + testEnvironment = environment.New(&environment.Config{ NamespacePrefix: fmt.Sprintf("smoke-ocr2vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), Test: t, }). AddHelm(evmConfig). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(t, err, "Error running test environment") diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 56d045fa097..8d71c5d08f8 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -20,20 +20,16 @@ func TestOCRBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(6). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) - nodeClients := env.GetAPIs() + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] linkTokenContract, err := env.ContractDeployer.DeployLinkTokenContract() @@ -44,7 +40,7 @@ func TestOCRBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockServer.Client, env.EVMClient.GetChainID().String()) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) require.NoError(t, err) err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) @@ -54,7 +50,7 @@ func TestOCRBasic(t *testing.T) { require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) - err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockServer.Client) + err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index 0bfc41eca71..f29cb4bc893 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "net/http" "strings" "testing" @@ -24,16 +25,12 @@ func TestRunLogBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). + WithMockAdapter(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) lt, err := env.ContractDeployer.DeployLinkTokenContract() require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") @@ -46,16 +43,16 @@ func TestRunLogBasic(t *testing.T) { err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) - err = env.MockServer.Client.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") + err = env.MockAdapter.SetAdapterBasedIntValuePath("/variable", []string{http.MethodPost}, 5) + require.NoError(t, err, "Setting mock adapter value path shouldn't fail") jobUUID := uuid.New() bta := client.BridgeTypeAttributes{ Name: fmt.Sprintf("five-%s", jobUUID.String()), - URL: fmt.Sprintf("%s/variable", env.MockServer.Client.Config.ClusterURL), + URL: fmt.Sprintf("%s/variable", env.MockAdapter.InternalEndpoint), } - err = env.CLNodes[0].API.MustCreateBridge(&bta) + err = env.ClCluster.Nodes[0].API.MustCreateBridge(&bta) require.NoError(t, err, "Creating bridge shouldn't fail") os := &client.DirectRequestTxPipelineSpec{ @@ -65,7 +62,7 @@ func TestRunLogBasic(t *testing.T) { ost, err := os.String() require.NoError(t, err, "Building observation source spec shouldn't fail") - _, err = env.CLNodes[0].API.MustCreateJob(&client.DirectRequestJobSpec{ + _, err = env.ClCluster.Nodes[0].API.MustCreateJob(&client.DirectRequestJobSpec{ Name: fmt.Sprintf("direct-request-%s", uuid.NewString()), MinIncomingConfirmations: "1", ContractAddress: oracle.Address(), @@ -82,7 +79,7 @@ func TestRunLogBasic(t *testing.T) { oracle.Address(), jobID, big.NewInt(1e18), - fmt.Sprintf("%s/variable", env.MockServer.Client.Config.ClusterURL), + fmt.Sprintf("%s/variable", env.MockAdapter.InternalEndpoint), "data,result", big.NewInt(100), ) diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 47f8cd8e30f..444d1ce20ee 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -26,16 +26,11 @@ func TestVRFBasic(t *testing.T) { env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). - WithMockServer(1). WithCLNodes(1). WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) lt, err := actions.DeployLINKToken(env.ContractDeployer) @@ -50,7 +45,7 @@ func TestVRFBasic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - for _, n := range env.CLNodes { + for _, n := range env.ClCluster.Nodes { nodeKey, err := n.API.MustCreateVRFKey() require.NoError(t, err, "Creating VRF key shouldn't fail") l.Debug().Interface("Key JSON", nodeKey).Msg("Created proving key") @@ -94,7 +89,7 @@ func TestVRFBasic(t *testing.T) { gom := gomega.NewGomegaWithT(t) timeout := time.Minute * 2 gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := env.CLNodes[0].API.MustReadRunsByJob(job.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") out, err := contracts.Consumer.RandomnessOutput(context.Background()) diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 18e9efeae44..c960bb6c691 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -27,13 +27,9 @@ func TestVRFv2Basic(t *testing.T) { WithGeth(). WithCLNodes(1). WithFunding(vrfConst.ChainlinkNodeFundingAmountEth). + WithStandardCleanup(). Build() require.NoError(t, err) - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) mockFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfConst.LinkEthFeedResponse) @@ -69,18 +65,18 @@ func TestVRFv2Basic(t *testing.T) { err = vrfv2_actions.FundVRFCoordinatorV2Subscription(lt, vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.SubID, vrfConst.VRFSubscriptionFundingAmountLink) require.NoError(t, err) - vrfV2jobs, err := vrfv2_actions.CreateVRFV2Jobs(env.GetAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) + vrfV2jobs, err := vrfv2_actions.CreateVRFV2Jobs(env.ClCluster.NodeAPIs(), vrfv2Contracts.Coordinator, env.EVMClient, vrfConst.MinimumConfirmations) require.NoError(t, err) // this part is here because VRFv2 can work with only a specific key // [[EVM.KeySpecific]] // Key = '...' - addr, err := env.CLNodes[0].API.PrimaryEthAddress() + addr, err := env.ClCluster.Nodes[0].API.PrimaryEthAddress() require.NoError(t, err) - nodeConfig := node.NewConfig(env.CLNodes[0].NodeConfig, + nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithVRFv2EVMEstimator(addr), ) - err = env.CLNodes[0].Restart(nodeConfig) + err = env.ClCluster.Nodes[0].Restart(nodeConfig) require.NoError(t, err) // test and assert @@ -98,7 +94,7 @@ func TestVRFv2Basic(t *testing.T) { timeout := time.Minute * 2 var lastRequestID *big.Int gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := env.CLNodes[0].API.MustReadRunsByJob(vrfV2jobs[0].Job.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfV2jobs[0].Job.Data.ID) g.Expect(err).ShouldNot(gomega.HaveOccurred()) g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically("==", 1)) lastRequestID, err = vrfv2Contracts.LoadTestConsumer.GetLastRequestId(context.Background()) diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index e26a4ed6b1f..c2cc0878b66 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -6,63 +6,61 @@ import ( "testing" "time" + "github.com/kelseyhightower/envconfig" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_constants" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) -func TestVRFv2PlusBilling(t *testing.T) { +func TestVRFv2Plus(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) + env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). - WithFunding(vrfv2plus_constants.ChainlinkNodeFundingAmountNative). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfv2plus_constants.LinkNativeFeedResponse) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, linkToken, mockETHLinkFeed, 1) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkToken, mockETHLinkFeed, 1, 1) require.NoError(t, err, "error setting up VRF v2_5 env") + subID := subIDs[0] + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("Juels Balance", subscription.Balance.String()). - Str("Native Token Balance", subscription.NativeBalance.String()). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("VRFV2 Plus With Link Billing", func(t *testing.T) { var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance - jobRunsBeforeTest, err := env.CLNodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert @@ -72,6 +70,8 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -82,7 +82,7 @@ func TestVRFv2PlusBilling(t *testing.T) { subBalanceAfterRequest := subscription.Balance require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) - jobRuns, err := env.CLNodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) @@ -91,7 +91,7 @@ func TestVRFv2PlusBilling(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -102,7 +102,7 @@ func TestVRFv2PlusBilling(t *testing.T) { var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance - jobRunsBeforeTest, err := env.CLNodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert @@ -112,6 +112,8 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, + vrfv2PlusConfig.RandomnessRequestCountPerRequest, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -121,7 +123,7 @@ func TestVRFv2PlusBilling(t *testing.T) { subBalanceAfterRequest := subscription.NativeBalance require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest) - jobRuns, err := env.CLNodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2PlusData.VRFJob.Data.ID) require.NoError(t, err, "error reading job runs") require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) @@ -130,7 +132,7 @@ func TestVRFv2PlusBilling(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -139,6 +141,7 @@ func TestVRFv2PlusBilling(t *testing.T) { wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( env, + &vrfv2PlusConfig, linkToken, mockETHLinkFeed, vrfv2PlusContracts.Coordinator, @@ -163,6 +166,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -185,20 +189,9 @@ func TestVRFv2PlusBilling(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - l.Debug(). - Str("Consumer Balance Before Request (Juels)", wrapperConsumerJuelsBalanceBeforeRequest.String()). - Str("Consumer Balance After Request (Juels)", wrapperConsumerJuelsBalanceAfterRequest.String()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid in Juels by Consumer Contract", consumerStatus.Paid.String()). - Str("Paid in Juels by Coordinator Sub", randomWordsFulfilledEvent.Payment.String()). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Request Fulfilment Status") - - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + vrfv2plus.LogFulfillmentDetailsLinkBilling(l, wrapperConsumerJuelsBalanceBeforeRequest, wrapperConsumerJuelsBalanceAfterRequest, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -221,6 +214,7 @@ func TestVRFv2PlusBilling(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -243,20 +237,9 @@ func TestVRFv2PlusBilling(t *testing.T) { //todo: uncomment when VRF-651 will be fixed //require.Equal(t, 1, consumerStatus.Paid.Cmp(randomWordsFulfilledEvent.Payment), "Expected Consumer contract pay more than the Coordinator Sub") - l.Debug(). - Str("Consumer Balance Before Request (WEI)", wrapperConsumerBalanceBeforeRequestWei.String()). - Str("Consumer Balance After Request (WEI)", wrapperConsumerBalanceAfterRequestWei.String()). - Bool("Fulfilment Status", consumerStatus.Fulfilled). - Str("Paid in Juels by Consumer Contract", consumerStatus.Paid.String()). - Str("Paid in Juels by Coordinator Sub", randomWordsFulfilledEvent.Payment.String()). - Str("RequestTimestamp", consumerStatus.RequestTimestamp.String()). - Str("FulfilmentTimestamp", consumerStatus.FulfilmentTimestamp.String()). - Str("RequestBlockNumber", consumerStatus.RequestBlockNumber.String()). - Str("FulfilmentBlockNumber", consumerStatus.FulfilmentBlockNumber.String()). - Str("TX Hash", randomWordsFulfilledEvent.Raw.TxHash.String()). - Msg("Random Words Request Fulfilment Status") - - require.Equal(t, vrfv2plus_constants.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + vrfv2plus.LogFulfillmentDetailsNativeBilling(l, wrapperConsumerBalanceBeforeRequestWei, wrapperConsumerBalanceAfterRequestWei, consumerStatus, randomWordsFulfilledEvent) + + require.Equal(t, vrfv2PlusConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -264,44 +247,39 @@ func TestVRFv2PlusBilling(t *testing.T) { }) } + func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig + err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + require.NoError(t, err) env, err := test_env.NewCLTestEnvBuilder(). WithTestLogger(t). WithGeth(). WithCLNodes(1). - WithFunding(vrfv2plus_constants.ChainlinkNodeFundingAmountNative). + WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") - t.Cleanup(func() { - if err := env.Cleanup(t); err != nil { - l.Error().Err(err).Msg("Error cleaning up test environment") - } - }) - env.ParallelTransactions(true) - mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, vrfv2plus_constants.LinkNativeFeedResponse) + mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2PlusContracts, subID, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, linkAddress, mockETHLinkFeedAddress, 2) + vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment(env, &vrfv2PlusConfig, linkAddress, mockETHLinkFeedAddress, 2, 1) require.NoError(t, err, "error setting up VRF v2_5 env") + subID := subIDs[0] + subscription, err := vrfv2PlusContracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("Juels Balance", subscription.Balance.String()). - Str("Native Token Balance", subscription.NativeBalance.String()). - Str("Subscription ID", subID.String()). - Str("Subscription Owner", subscription.Owner.String()). - Interface("Subscription Consumers", subscription.Consumers). - Msg("Subscription Data") + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) activeSubIdsOldCoordinatorBeforeMigration, err := vrfv2PlusContracts.Coordinator.GetActiveSubscriptionIds(context.Background(), big.NewInt(0), big.NewInt(0)) require.NoError(t, err, "error occurred getting active sub ids") @@ -322,12 +300,15 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, errors.Wrap(err, vrfv2plus.ErrRegisteringProvingKey)) err = newCoordinator.SetConfig( - vrfv2plus_constants.MinimumConfirmations, - vrfv2plus_constants.MaxGasLimitVRFCoordinatorConfig, - vrfv2plus_constants.StalenessSeconds, - vrfv2plus_constants.GasAfterPaymentCalculation, - vrfv2plus_constants.LinkNativeFeedResponse, - vrfv2plus_constants.VRFCoordinatorV2PlusUpgradedVersionFeeConfig, + vrfv2PlusConfig.MinimumConfirmations, + vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + vrfv2PlusConfig.StalenessSeconds, + vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ + FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + }, ) err = newCoordinator.SetLINKAndLINKNativeFeed(linkAddress.Address(), mockETHLinkFeedAddress.Address()) @@ -336,12 +317,12 @@ func TestVRFv2PlusMigration(t *testing.T) { require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) _, err = vrfv2plus.CreateVRFV2PlusJob( - env.GetAPIs()[0], + env.ClCluster.NodeAPIs()[0], newCoordinator.Address(), vrfv2PlusData.PrimaryEthAddress, vrfv2PlusData.VRFKey.Data.ID, vrfv2PlusData.ChainID.String(), - vrfv2plus_constants.MinimumConfirmations, + vrfv2PlusConfig.MinimumConfirmations, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) @@ -367,11 +348,7 @@ func TestVRFv2PlusMigration(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - l.Debug(). - Str("Subscription ID", migrationCompletedEvent.SubId.String()). - Str("Migrated From Coordinator", vrfv2PlusContracts.Coordinator.Address()). - Str("Migrated To Coordinator", migrationCompletedEvent.NewCoordinator.String()). - Msg("MigrationCompleted Event") + vrfv2plus.LogMigrationCompletedEvent(l, migrationCompletedEvent, vrfv2PlusContracts) oldCoordinatorLinkTotalBalanceAfterMigration, oldCoordinatorEthTotalBalanceAfterMigration, err := vrfv2plus.GetCoordinatorTotalBalance(vrfv2PlusContracts.Coordinator) require.NoError(t, err) @@ -382,14 +359,7 @@ func TestVRFv2PlusMigration(t *testing.T) { migratedSubscription, err := newCoordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - l.Debug(). - Str("New Coordinator", newCoordinator.Address()). - Str("Subscription ID", subID.String()). - Str("Juels Balance", migratedSubscription.Balance.String()). - Str("Native Token Balance", migratedSubscription.NativeBalance.String()). - Str("Subscription Owner", migratedSubscription.Owner.String()). - Interface("Subscription Consumers", migratedSubscription.Consumers). - Msg("Subscription Data After Migration to New Coordinator") + vrfv2plus.LogSubDetailsAfterMigration(l, newCoordinator, subID, migratedSubscription) //Verify that Coordinators were updated in Consumers for _, consumer := range vrfv2PlusContracts.LoadTestConsumers { @@ -438,6 +408,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -449,6 +420,7 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, + &vrfv2PlusConfig, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index ba0cc23b23b..466eb97fdd3 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -5,6 +5,9 @@ import ( "fmt" "math" "math/big" + "os" + "os/signal" + "syscall" "testing" "time" @@ -13,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/slack-go/slack" "github.com/stretchr/testify/require" @@ -41,6 +45,10 @@ type KeeperBenchmarkTest struct { Inputs KeeperBenchmarkTestInputs TestReporter testreporters.KeeperBenchmarkTestReporter + t *testing.T + log zerolog.Logger + startingBlock *big.Int + keeperRegistries []contracts.KeeperRegistry keeperRegistrars []contracts.KeeperRegistrar keeperConsumerContracts []contracts.AutomationConsumerBenchmark @@ -57,6 +65,7 @@ type KeeperBenchmarkTest struct { gasFeed contracts.MockGasFeed } +// UpkeepConfig dictates details of how the test's upkeep contracts should be called and configured type UpkeepConfig struct { NumberOfUpkeeps int // Number of upkeep contracts BlockRange int64 // How many blocks to run the test for @@ -67,6 +76,8 @@ type UpkeepConfig struct { FirstEligibleBuffer int64 // How many blocks to add to randomised first eligible block, set to 0 to disable randomised first eligible block } +// PreDeployedContracts are contracts that are already deployed on a (usually) live testnet chain, so re-deployment +// in unnecessary type PreDeployedContracts struct { RegistryAddress string RegistrarAddress string @@ -92,18 +103,19 @@ type KeeperBenchmarkTestInputs struct { } // NewKeeperBenchmarkTest prepares a new keeper benchmark test to be run -func NewKeeperBenchmarkTest(inputs KeeperBenchmarkTestInputs) *KeeperBenchmarkTest { +func NewKeeperBenchmarkTest(t *testing.T, inputs KeeperBenchmarkTestInputs) *KeeperBenchmarkTest { return &KeeperBenchmarkTest{ Inputs: inputs, + t: t, + log: logging.GetTestLogger(t), } } // Setup prepares contracts for the test -func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { startTime := time.Now() k.TestReporter.Summary.StartTime = startTime.UnixMilli() - k.ensureInputValues(t) + k.ensureInputValues() k.env = env k.namespace = k.env.Cfg.Namespace inputs := k.Inputs @@ -112,70 +124,65 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) k.keeperRegistrars = make([]contracts.KeeperRegistrar, len(inputs.RegistryVersions)) k.keeperConsumerContracts = make([]contracts.AutomationConsumerBenchmark, len(inputs.RegistryVersions)) k.upkeepIDs = make([][]*big.Int, len(inputs.RegistryVersions)) - l.Debug().Interface("TestInputs", inputs).Msg("Setting up benchmark test") + k.log.Debug().Interface("TestInputs", inputs).Msg("Setting up benchmark test") var err error // Connect to networks and prepare for contract deployment - k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient, l) - require.NoError(t, err, "Building a new contract deployer shouldn't fail") + k.contractDeployer, err = contracts.NewContractDeployer(k.chainClient, k.log) + require.NoError(k.t, err, "Building a new contract deployer shouldn't fail") k.chainlinkNodes, err = client.ConnectChainlinkNodes(k.env) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") + require.NoError(k.t, err, "Connecting to chainlink nodes shouldn't fail") k.chainClient.ParallelTransactions(true) if len(inputs.RegistryVersions) > 1 && !inputs.ForceSingleTxnKey { for nodeIndex, node := range k.chainlinkNodes { for registryIndex := 1; registryIndex < len(inputs.RegistryVersions); registryIndex++ { - l.Debug().Str("URL", node.URL()).Int("NodeIndex", nodeIndex).Int("RegistryIndex", registryIndex).Msg("Create Tx key") + k.log.Debug().Str("URL", node.URL()).Int("NodeIndex", nodeIndex).Int("RegistryIndex", registryIndex).Msg("Create Tx key") _, _, err := node.CreateTxKey("evm", k.Inputs.BlockchainClient.GetChainID().String()) - require.NoError(t, err, "Creating transaction key shouldn't fail") + require.NoError(k.t, err, "Creating transaction key shouldn't fail") } } } - var () - c := inputs.Contracts if common.IsHexAddress(c.LinkTokenAddress) { k.linkToken, err = k.contractDeployer.LoadLinkToken(common.HexToAddress(c.LinkTokenAddress)) - require.NoError(t, err, "Loading Link Token Contract shouldn't fail") + require.NoError(k.t, err, "Loading Link Token Contract shouldn't fail") } else { k.linkToken, err = k.contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + require.NoError(k.t, err, "Deploying Link Token Contract shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for LINK Contract deployment") + require.NoError(k.t, err, "Failed waiting for LINK Contract deployment") } if common.IsHexAddress(c.EthFeedAddress) { k.ethFeed, err = k.contractDeployer.LoadETHLINKFeed(common.HexToAddress(c.EthFeedAddress)) - require.NoError(t, err, "Loading ETH-Link feed Contract shouldn't fail") + require.NoError(k.t, err, "Loading ETH-Link feed Contract shouldn't fail") } else { k.ethFeed, err = k.contractDeployer.DeployMockETHLINKFeed(big.NewInt(2e18)) - require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail") + require.NoError(k.t, err, "Deploying mock ETH-Link feed shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for ETH-Link feed Contract deployment") + require.NoError(k.t, err, "Failed waiting for ETH-Link feed Contract deployment") } if common.IsHexAddress(c.GasFeedAddress) { k.gasFeed, err = k.contractDeployer.LoadGasFeed(common.HexToAddress(c.GasFeedAddress)) - require.NoError(t, err, "Loading Gas feed Contract shouldn't fail") + require.NoError(k.t, err, "Loading Gas feed Contract shouldn't fail") } else { k.gasFeed, err = k.contractDeployer.DeployMockGasFeed(big.NewInt(2e11)) - require.NoError(t, err, "Deploying mock gas feed shouldn't fail") + require.NoError(k.t, err, "Deploying mock gas feed shouldn't fail") err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for mock gas feed Contract deployment") + require.NoError(k.t, err, "Failed waiting for mock gas feed Contract deployment") } err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for mock feeds to deploy") + require.NoError(k.t, err, "Failed waiting for mock feeds to deploy") for index := range inputs.RegistryVersions { - l.Info().Int("Index", index).Msg("Starting Test Setup") + k.log.Info().Int("Index", index).Msg("Starting Test Setup") - k.DeployBenchmarkKeeperContracts( - t, - index, - ) + k.DeployBenchmarkKeeperContracts(index) } var keysToFund = inputs.RegistryVersions @@ -190,19 +197,18 @@ func (k *KeeperBenchmarkTest) Setup(t *testing.T, env *environment.Environment) nodesToFund = k.chainlinkNodes[1:] } err = actions.FundChainlinkNodesAddress(nodesToFund, k.chainClient, k.Inputs.ChainlinkNodeFunding, index) - require.NoError(t, err, "Funding Chainlink nodes shouldn't fail") + require.NoError(k.t, err, "Funding Chainlink nodes shouldn't fail") } - l.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") + k.log.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") err = k.SendSlackNotification(nil) if err != nil { - l.Warn().Msg("Sending test start slack notification failed") + k.log.Warn().Msg("Sending test start slack notification failed") } } // Run runs the keeper benchmark test -func (k *KeeperBenchmarkTest) Run(t *testing.T) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) Run() { u := k.Inputs.Upkeeps k.TestReporter.Summary.Load.TotalCheckGasPerBlock = int64(u.NumberOfUpkeeps) * u.CheckGasToBurn k.TestReporter.Summary.Load.TotalPerformGasPerBlock = int64((float64(u.NumberOfUpkeeps) / @@ -223,6 +229,9 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { "NumberOfRegistries": len(k.keeperRegistries), } inputs := k.Inputs + startingBlock, err := k.chainClient.LatestBlockNumber(context.Background()) + require.NoError(k.t, err, "Error getting latest block number") + k.startingBlock = big.NewInt(0).SetUint64(startingBlock) startTime := time.Now() nodesWithoutBootstrap := k.chainlinkNodes[1:] @@ -234,22 +243,22 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { txKeyId = 0 } ocrConfig, err := actions.BuildAutoOCR2ConfigVarsWithKeyIndex( - t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, k.keeperRegistrars[rIndex].Address(), k.Inputs.DeltaStage, txKeyId, + k.t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, k.keeperRegistrars[rIndex].Address(), k.Inputs.DeltaStage, txKeyId, common.Address{}, ) - require.NoError(t, err, "Building OCR config shouldn't fail") + require.NoError(k.t, err, "Building OCR config shouldn't fail") // Send keeper jobs to registry and chainlink nodes if inputs.RegistryVersions[rIndex] == ethereum.RegistryVersion_2_0 || inputs.RegistryVersions[rIndex] == ethereum.RegistryVersion_2_1 { - actions.CreateOCRKeeperJobs(t, k.chainlinkNodes, k.keeperRegistries[rIndex].Address(), k.chainClient.GetChainID().Int64(), txKeyId, inputs.RegistryVersions[rIndex]) + actions.CreateOCRKeeperJobs(k.t, k.chainlinkNodes, k.keeperRegistries[rIndex].Address(), k.chainClient.GetChainID().Int64(), txKeyId, inputs.RegistryVersions[rIndex]) err = k.keeperRegistries[rIndex].SetConfig(*inputs.KeeperRegistrySettings, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(k.t, err, "Registry config should be be set successfully") // Give time for OCR nodes to bootstrap time.Sleep(1 * time.Minute) } else { - actions.CreateKeeperJobsWithKeyIndex(t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig, k.chainClient.GetChainID().String()) + actions.CreateKeeperJobsWithKeyIndex(k.t, k.chainlinkNodes, k.keeperRegistries[rIndex], txKeyId, ocrConfig, k.chainClient.GetChainID().String()) } err = k.chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for registry setConfig") + require.NoError(k.t, err, "Error waiting for registry setConfig") } for rIndex := range k.keeperRegistries { @@ -264,7 +273,7 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { &k.TestReporter, int64(index), inputs.Upkeeps.FirstEligibleBuffer, - l, + k.log, ), ) } @@ -275,32 +284,83 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { k.chainClient.DeleteHeaderEventSubscription(fmt.Sprintf("Keeper Tracker %d %d", rIndex, index)) } } - }() - logSubscriptionStop := make(chan bool) + + // Main test loop + k.observeUpkeepEvents() + err = k.chainClient.WaitForEvents() + require.NoError(k.t, err, "Error waiting for keeper subscriptions") + + // Collect logs for each registry to calculate test metrics + registryLogs := make([][]types.Log, len(k.keeperRegistries)) + for rIndex := range k.keeperRegistries { + var ( + logs []types.Log + timeout = 5 * time.Second + addr = k.keeperRegistries[rIndex].Address() + filterQuery = geth.FilterQuery{ + Addresses: []common.Address{common.HexToAddress(addr)}, + FromBlock: k.startingBlock, + } + err = fmt.Errorf("initial error") // to ensure our for loop runs at least once + ) + for err != nil { // This RPC call can possibly time out or otherwise die. Failure is not an option, keep retrying to get our stats. + ctx, cancel := context.WithTimeout(context.Background(), timeout) + logs, err = k.chainClient.FilterLogs(ctx, filterQuery) + cancel() + if err != nil { + k.log.Error().Err(err). + Interface("Filter Query", filterQuery). + Str("Timeout", timeout.String()). + Msg("Error getting logs from chain, trying again") + } else { + k.log.Info().Int("Log Count", len(logs)).Str("Registry Address", addr).Msg("Collected logs") + } + } + registryLogs[rIndex] = logs + } + + // Count reverts and stale upkeeps for rIndex := range k.keeperRegistries { - k.subscribeToUpkeepPerformedEvent(t, logSubscriptionStop, &k.TestReporter, rIndex) + contractABI := k.contractABI(rIndex) + for _, l := range registryLogs[rIndex] { + log := l + eventDetails, err := contractABI.EventByID(log.Topics[0]) + if err != nil { + k.log.Error().Err(err).Str("Log Hash", log.TxHash.Hex()).Msg("Error getting event details for log, report data inaccurate") + break + } + if eventDetails.Name == "UpkeepPerformed" { + parsedLog, err := k.keeperRegistries[rIndex].ParseUpkeepPerformedLog(&log) + if err != nil { + k.log.Error().Err(err).Str("Log Hash", log.TxHash.Hex()).Msg("Error parsing upkeep performed log, report data inaccurate") + break + } + if !parsedLog.Success { + k.TestReporter.NumRevertedUpkeeps++ + } + } else if eventDetails.Name == "StaleUpkeepReport" { + k.TestReporter.NumStaleUpkeepReports++ + } + } } - err := k.chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for keeper subscriptions") - close(logSubscriptionStop) for _, chainlinkNode := range k.chainlinkNodes { txData, err := chainlinkNode.MustReadTransactionAttempts() if err != nil { - l.Error().Err(err).Msg("Error reading transaction attempts from Chainlink Node") + k.log.Error().Err(err).Msg("Error reading transaction attempts from Chainlink Node") } k.TestReporter.AttemptedChainlinkTransactions = append(k.TestReporter.AttemptedChainlinkTransactions, txData) } k.TestReporter.Summary.Config.Chainlink, err = k.env.ResourcesSummary("app=chainlink-0") if err != nil { - l.Error().Err(err).Msg("Error getting resource summary of chainlink node") + k.log.Error().Err(err).Msg("Error getting resource summary of chainlink node") } k.TestReporter.Summary.Config.Geth, err = k.env.ResourcesSummary("app=geth") if err != nil && k.Inputs.BlockchainClient.NetworkSimulated() { - l.Error().Err(err).Msg("Error getting resource summary of geth node") + k.log.Error().Err(err).Msg("Error getting resource summary of geth node") } endTime := time.Now() @@ -309,139 +369,178 @@ func (k *KeeperBenchmarkTest) Run(t *testing.T) { for rIndex := range k.keeperRegistries { if inputs.DeleteJobsOnEnd { // Delete keeper jobs on chainlink nodes - actions.DeleteKeeperJobsWithId(t, k.chainlinkNodes, rIndex+1) + actions.DeleteKeeperJobsWithId(k.t, k.chainlinkNodes, rIndex+1) } } - l.Info().Str("Run Time", endTime.Sub(startTime).String()).Msg("Finished Keeper Benchmark Test") + k.log.Info().Str("Run Time", endTime.Sub(startTime).String()).Msg("Finished Keeper Benchmark Test") } -// subscribeToUpkeepPerformedEvent subscribes to the event log for UpkeepPerformed event and -// counts the number of times it was unsuccessful -func (k *KeeperBenchmarkTest) subscribeToUpkeepPerformedEvent( - t *testing.T, - doneChan chan bool, - metricsReporter *testreporters.KeeperBenchmarkTestReporter, - rIndex int, +// TearDownVals returns the networks that the test is running on +func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( + *testing.T, + string, + []*client.ChainlinkK8sClient, + reportModel.TestReporter, + blockchain.EVMClient, ) { - l := logging.GetTestLogger(t) - contractABI, err := keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() - require.NoError(t, err, "Error getting ABI") - switch k.Inputs.RegistryVersions[rIndex] { - case ethereum.RegistryVersion_1_0, ethereum.RegistryVersion_1_1: - contractABI, err = keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_1_2: - contractABI, err = keeper_registry_wrapper1_2.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_1_3: - contractABI, err = keeper_registry_wrapper1_3.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_2_0: - contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() - case ethereum.RegistryVersion_2_1: - contractABI, err = iregistry21.IKeeperRegistryMasterMetaData.GetAbi() - default: - contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() - } + return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient +} - require.NoError(t, err, "Getting contract abi for registry shouldn't fail") - query := geth.FilterQuery{ - Addresses: []common.Address{common.HexToAddress(k.keeperRegistries[rIndex].Address())}, - } +// ********************* +// ****** Helpers ****** +// ********************* + +// observeUpkeepEvents subscribes to Upkeep events on deployed registries and logs them +// WARNING: This should only be used for observation and logging. This isn't a reliable way to build a final report +// due to how fragile subscriptions can be +func (k *KeeperBenchmarkTest) observeUpkeepEvents() { eventLogs := make(chan types.Log) - sub, err := k.chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) - require.NoError(t, err, "Subscribing to upkeep performed events log shouldn't fail") + registryAddresses := make([]common.Address, len(k.keeperRegistries)) + addressIndexMap := map[common.Address]int{} + for index, registry := range k.keeperRegistries { + registryAddresses[index] = common.HexToAddress(registry.Address()) + addressIndexMap[registryAddresses[index]] = index + } + filterQuery := geth.FilterQuery{ + Addresses: registryAddresses, + FromBlock: k.startingBlock, + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + sub, err := k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) + cancel() + require.NoError(k.t, err, "Subscribing to upkeep performed events log shouldn't fail") + + interruption := make(chan os.Signal, 1) + signal.Notify(interruption, os.Kill, os.Interrupt, syscall.SIGTERM) + go func() { - var numRevertedUpkeeps int64 - var numStaleReports int64 for { select { + case <-interruption: + k.log.Warn().Msg("Received interrupt signal, test container restarting. Dashboard view will be inaccurate.") case err := <-sub.Err(): - l.Error().Err(err).Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") - sub.Unsubscribe() - - sub, err = k.chainClient.SubscribeFilterLogs(context.Background(), query, eventLogs) - require.NoError(t, err, "Error re-subscribing to event logs") + backoff := time.Second + for err != nil { // Keep retrying until we get a successful subscription + k.log.Error(). + Err(err). + Interface("Query", filterQuery). + Str("Backoff", backoff.String()). + Msg("Error while subscribing to Keeper Event Logs. Resubscribing...") + + ctx, cancel := context.WithTimeout(context.Background(), backoff) + sub, err = k.chainClient.SubscribeFilterLogs(ctx, filterQuery, eventLogs) + cancel() + if err != nil { + time.Sleep(backoff) + backoff = time.Duration(math.Min(float64(backoff)*2, float64(30*time.Second))) + } + } + log.Info().Msg("Resubscribed to Keeper Event Logs") case vLog := <-eventLogs: + rIndex, ok := addressIndexMap[vLog.Address] + if !ok { + k.log.Error().Str("Address", vLog.Address.Hex()).Msg("Received log from unknown registry") + continue + } + contractABI := k.contractABI(rIndex) eventDetails, err := contractABI.EventByID(vLog.Topics[0]) - require.NoError(t, err, "Getting event details for subscribed log shouldn't fail") + require.NoError(k.t, err, "Getting event details for subscribed log shouldn't fail") if eventDetails.Name != "UpkeepPerformed" && eventDetails.Name != "StaleUpkeepReport" { // Skip non upkeepPerformed Logs continue } + if vLog.Removed { + k.log.Warn(). + Str("Name", eventDetails.Name). + Str("Registry", k.keeperRegistries[rIndex].Address()). + Msg("Got removed log") + } if eventDetails.Name == "UpkeepPerformed" { parsedLog, err := k.keeperRegistries[rIndex].ParseUpkeepPerformedLog(&vLog) - require.NoError(t, err, "Parsing upkeep performed log shouldn't fail") + require.NoError(k.t, err, "Parsing upkeep performed log shouldn't fail") if parsedLog.Success { - l.Info(). + k.log.Info(). Str("Upkeep ID", parsedLog.Id.String()). Bool("Success", parsedLog.Success). Str("From", parsedLog.From.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got successful Upkeep Performed log on Registry") - } else { - l.Warn(). + k.log.Warn(). Str("Upkeep ID", parsedLog.Id.String()). Bool("Success", parsedLog.Success). Str("From", parsedLog.From.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got reverted Upkeep Performed log on Registry") - numRevertedUpkeeps++ } } else if eventDetails.Name == "StaleUpkeepReport" { parsedLog, err := k.keeperRegistries[rIndex].ParseStaleUpkeepReportLog(&vLog) - require.NoError(t, err, "Parsing stale upkeep report log shouldn't fail") - l.Warn(). + require.NoError(k.t, err, "Parsing stale upkeep report log shouldn't fail") + k.log.Warn(). Str("Upkeep ID", parsedLog.Id.String()). Str("Registry", k.keeperRegistries[rIndex].Address()). Msg("Got stale Upkeep report log on Registry") - numStaleReports++ } - - case <-doneChan: - metricsReporter.NumRevertedUpkeeps = numRevertedUpkeeps - metricsReporter.NumStaleUpkeepReports = numStaleReports - return + case <-k.chainClient.ConnectionIssue(): + k.log.Warn().Msg("RPC connection issue detected.") + case <-k.chainClient.ConnectionRestored(): + k.log.Info().Msg("RPC connection restored.") } } }() } -// TearDownVals returns the networks that the test is running on -func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( - *testing.T, - string, - []*client.ChainlinkK8sClient, - reportModel.TestReporter, - blockchain.EVMClient, -) { - return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient +// contractABI returns the ABI of the proper keeper registry contract +func (k *KeeperBenchmarkTest) contractABI(rIndex int) *abi.ABI { + var ( + contractABI *abi.ABI + err error + ) + switch k.Inputs.RegistryVersions[rIndex] { + case ethereum.RegistryVersion_1_0, ethereum.RegistryVersion_1_1: + contractABI, err = keeper_registry_wrapper1_1.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_1_2: + contractABI, err = keeper_registry_wrapper1_2.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_1_3: + contractABI, err = keeper_registry_wrapper1_3.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_2_0: + contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() + case ethereum.RegistryVersion_2_1: + contractABI, err = iregistry21.IKeeperRegistryMasterMetaData.GetAbi() + default: + contractABI, err = keeper_registry_wrapper2_0.KeeperRegistryMetaData.GetAbi() + } + require.NoError(k.t, err, "Getting contract ABI shouldn't fail") + return contractABI } // ensureValues ensures that all values needed to run the test are present -func (k *KeeperBenchmarkTest) ensureInputValues(t *testing.T) { +func (k *KeeperBenchmarkTest) ensureInputValues() { inputs := k.Inputs - require.NotNil(t, inputs.BlockchainClient, "Need a valid blockchain client to use for the test") + require.NotNil(k.t, inputs.BlockchainClient, "Need a valid blockchain client to use for the test") k.chainClient = inputs.BlockchainClient - require.GreaterOrEqual(t, inputs.Upkeeps.NumberOfUpkeeps, 1, "Expecting at least 1 keeper contracts") + require.GreaterOrEqual(k.t, inputs.Upkeeps.NumberOfUpkeeps, 1, "Expecting at least 1 keeper contracts") if inputs.Timeout == 0 { - require.Greater(t, inputs.Upkeeps.BlockRange, int64(0), "If no `timeout` is provided, a `testBlockRange` is required") + require.Greater(k.t, inputs.Upkeeps.BlockRange, int64(0), "If no `timeout` is provided, a `testBlockRange` is required") } else if inputs.Upkeeps.BlockRange <= 0 { - require.GreaterOrEqual(t, inputs.Timeout, time.Second, "If no `testBlockRange` is provided a `timeout` is required") + require.GreaterOrEqual(k.t, inputs.Timeout, time.Second, "If no `testBlockRange` is provided a `timeout` is required") } - require.NotNil(t, inputs.KeeperRegistrySettings, "You need to set KeeperRegistrySettings") - require.NotNil(t, k.Inputs.ChainlinkNodeFunding, "You need to set a funding amount for chainlink nodes") + require.NotNil(k.t, inputs.KeeperRegistrySettings, "You need to set KeeperRegistrySettings") + require.NotNil(k.t, k.Inputs.ChainlinkNodeFunding, "You need to set a funding amount for chainlink nodes") clFunds, _ := k.Inputs.ChainlinkNodeFunding.Float64() - require.GreaterOrEqual(t, clFunds, 0.0, "Expecting Chainlink node funding to be more than 0 ETH") - require.Greater(t, inputs.Upkeeps.CheckGasToBurn, int64(0), "You need to set an expected amount of gas to burn on checkUpkeep()") + require.GreaterOrEqual(k.t, clFunds, 0.0, "Expecting Chainlink node funding to be more than 0 ETH") + require.Greater(k.t, inputs.Upkeeps.CheckGasToBurn, int64(0), "You need to set an expected amount of gas to burn on checkUpkeep()") require.GreaterOrEqual( - t, int64(inputs.KeeperRegistrySettings.CheckGasLimit), inputs.Upkeeps.CheckGasToBurn, "CheckGasLimit should be >= CheckGasToBurn", + k.t, int64(inputs.KeeperRegistrySettings.CheckGasLimit), inputs.Upkeeps.CheckGasToBurn, "CheckGasLimit should be >= CheckGasToBurn", ) - require.Greater(t, inputs.Upkeeps.PerformGasToBurn, int64(0), "You need to set an expected amount of gas to burn on performUpkeep()") - require.NotNil(t, inputs.UpkeepSLA, "Expected UpkeepSLA to be set") - require.NotNil(t, inputs.Upkeeps.FirstEligibleBuffer, "You need to set FirstEligibleBuffer") - require.NotNil(t, inputs.RegistryVersions[0], "You need to set RegistryVersion") - require.NotNil(t, inputs.BlockTime, "You need to set BlockTime") + require.Greater(k.t, inputs.Upkeeps.PerformGasToBurn, int64(0), "You need to set an expected amount of gas to burn on performUpkeep()") + require.NotNil(k.t, inputs.UpkeepSLA, "Expected UpkeepSLA to be set") + require.NotNil(k.t, inputs.Upkeeps.FirstEligibleBuffer, "You need to set FirstEligibleBuffer") + require.NotNil(k.t, inputs.RegistryVersions[0], "You need to set RegistryVersion") + require.NotNil(k.t, inputs.BlockTime, "You need to set BlockTime") if k.Inputs.DeltaStage == 0 { k.Inputs.DeltaStage = k.Inputs.BlockTime * 5 @@ -473,11 +572,7 @@ func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client) e } // DeployBenchmarkKeeperContracts deploys a set amount of keeper Benchmark contracts registered to a single registry -func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( - t *testing.T, - index int, -) { - l := logging.GetTestLogger(t) +func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int) { registryVersion := k.Inputs.RegistryVersions[index] k.Inputs.KeeperRegistrySettings.RegistryVersion = registryVersion upkeep := k.Inputs.Upkeeps @@ -488,7 +583,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( // Contract deployment is different for legacy keepers and OCR automation if registryVersion <= ethereum.RegistryVersion_1_3 { // Legacy keeper - v1.X - registry = actions.DeployKeeperRegistry(t, k.contractDeployer, k.chainClient, + registry = actions.DeployKeeperRegistry(k.t, k.contractDeployer, k.chainClient, &contracts.KeeperRegistryOpts{ RegistryVersion: registryVersion, LinkAddr: k.linkToken.Address(), @@ -502,7 +597,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( // Fund the registry with 1 LINK * amount of AutomationConsumerBenchmark contracts err := k.linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(k.Inputs.Upkeeps.NumberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") + require.NoError(k.t, err, "Funding keeper registry contract shouldn't fail") registrarSettings := contracts.KeeperRegistrarSettings{ AutoApproveConfigType: 2, @@ -510,29 +605,30 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( RegistryAddr: registry.Address(), MinLinkJuels: big.NewInt(0), } - registrar = actions.DeployKeeperRegistrar(t, registryVersion, k.linkToken, registrarSettings, k.contractDeployer, k.chainClient, registry) + registrar = actions.DeployKeeperRegistrar(k.t, registryVersion, k.linkToken, registrarSettings, k.contractDeployer, k.chainClient, registry) } else { // OCR automation - v2.X registry, registrar = actions.DeployAutoOCRRegistryAndRegistrar( - t, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, k.contractDeployer, k.chainClient) + k.t, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, k.contractDeployer, k.chainClient, + ) // Fund the registry with LINK err := k.linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(k.Inputs.Upkeeps.NumberOfUpkeeps)))) - require.NoError(t, err, "Funding keeper registry contract shouldn't fail") - ocrConfig, err := actions.BuildAutoOCR2ConfigVars(t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage) - l.Debug().Interface("KeeperRegistrySettings", *k.Inputs.KeeperRegistrySettings).Interface("OCRConfig", ocrConfig).Msg("Config") - require.NoError(t, err, "Error building OCR config vars") + require.NoError(k.t, err, "Funding keeper registry contract shouldn't fail") + ocrConfig, err := actions.BuildAutoOCR2ConfigVars(k.t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage) + k.log.Debug().Interface("KeeperRegistrySettings", *k.Inputs.KeeperRegistrySettings).Interface("OCRConfig", ocrConfig).Msg("Config") + require.NoError(k.t, err, "Error building OCR config vars") err = registry.SetConfig(*k.Inputs.KeeperRegistrySettings, ocrConfig) - require.NoError(t, err, "Registry config should be be set successfully") + require.NoError(k.t, err, "Registry config should be be set successfully") } - consumer := DeployKeeperConsumersBenchmark(t, k.contractDeployer, k.chainClient) + consumer := k.DeployKeeperConsumersBenchmark() var upkeepAddresses []string checkData := make([][]byte, 0) uint256Ty, err := abi.NewType("uint256", "uint256", nil) - require.NoError(t, err) + require.NoError(k.t, err) var data []byte checkDataAbi := abi.Arguments{ { @@ -560,8 +656,8 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( data, err = checkDataAbi.Pack( big.NewInt(int64(i)), big.NewInt(upkeep.BlockInterval), big.NewInt(upkeep.BlockRange), big.NewInt(upkeep.CheckGasToBurn), big.NewInt(upkeep.PerformGasToBurn), big.NewInt(upkeep.FirstEligibleBuffer)) - require.NoError(t, err) - l.Debug().Str("checkData: ", hexutil.Encode(data)).Int("id", i).Msg("checkData computed") + require.NoError(k.t, err) + k.log.Debug().Str("checkData: ", hexutil.Encode(data)).Int("id", i).Msg("checkData computed") checkData = append(checkData, data) } linkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(upkeep.BlockRange/upkeep.BlockInterval)) @@ -575,7 +671,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( linkFunds = big.NewInt(0).Add(linkFunds, minLinkBalance) - upkeepIds := actions.RegisterUpkeepContractsWithCheckData(t, k.linkToken, linkFunds, k.chainClient, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false) + upkeepIds := actions.RegisterUpkeepContractsWithCheckData(k.t, k.linkToken, linkFunds, k.chainClient, uint32(upkeep.UpkeepGasLimit), registry, registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false, false) k.keeperRegistries[index] = registry k.keeperRegistrars[index] = registrar @@ -583,27 +679,21 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts( k.keeperConsumerContracts[index] = consumer } -func DeployKeeperConsumersBenchmark( - t *testing.T, - contractDeployer contracts.ContractDeployer, - client blockchain.EVMClient, -) contracts.AutomationConsumerBenchmark { - l := logging.GetTestLogger(t) - +func (k *KeeperBenchmarkTest) DeployKeeperConsumersBenchmark() contracts.AutomationConsumerBenchmark { // Deploy consumer - keeperConsumerInstance, err := contractDeployer.DeployKeeperConsumerBenchmark() + keeperConsumerInstance, err := k.contractDeployer.DeployKeeperConsumerBenchmark() if err != nil { - l.Error().Err(err).Msg("Deploying AutomationConsumerBenchmark instance %d shouldn't fail") - keeperConsumerInstance, err = contractDeployer.DeployKeeperConsumerBenchmark() - require.NoError(t, err, "Error deploying AutomationConsumerBenchmark") + k.log.Error().Err(err).Msg("Deploying AutomationConsumerBenchmark instance %d shouldn't fail") + keeperConsumerInstance, err = k.contractDeployer.DeployKeeperConsumerBenchmark() + require.NoError(k.t, err, "Error deploying AutomationConsumerBenchmark") } - l.Debug(). + k.log.Debug(). Str("Contract Address", keeperConsumerInstance.Address()). Msg("Deployed Keeper Benchmark Contract") - err = client.WaitForEvents() - require.NoError(t, err, "Failed waiting for to deploy all keeper consumer contracts") - l.Info().Msg("Successfully deployed all Keeper Consumer Contracts") + err = k.chainClient.WaitForEvents() + require.NoError(k.t, err, "Failed waiting for to deploy all keeper consumer contracts") + k.log.Info().Msg("Successfully deployed all Keeper Consumer Contracts") return keeperConsumerInstance } diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 5f12995cc06..048f3124ad9 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -4,7 +4,7 @@ package testsetups import ( "context" "fmt" - "io/ioutil" + "math" "math/big" "math/rand" "os" @@ -24,6 +24,8 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/chainlink-env/environment" "github.com/smartcontractkit/chainlink-env/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-env/pkg/helm/ethereum" @@ -32,10 +34,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" "github.com/smartcontractkit/chainlink-testing-framework/logging" - reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" - "github.com/smartcontractkit/chainlink-testing-framework/networks" + reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" @@ -44,7 +44,10 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/testreporters" ) -const saveFileLocation = "/persistence/ocr-soak-test-state.toml" +const ( + saveFileLocation = "/persistence/ocr-soak-test-state.toml" + interruptedExitCode = 3 +) // OCRSoakTest defines a typical OCR soak test type OCRSoakTest struct { @@ -118,8 +121,7 @@ func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { ocrRoundStates: make([]*testreporters.OCRRoundState, 0), ocrInstanceMap: make(map[string]contracts.OffchainAggregator), } - test.ensureInputValues() - return test, nil + return test, test.ensureInputValues() } // DeployEnvironment deploys the test environment, starting all Chainlink nodes and other components for the test @@ -131,18 +133,20 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } nsPre = fmt.Sprintf("%s%s", nsPre, strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")) baseEnvironmentConfig := &environment.Config{ - TTL: time.Hour * 720, // 30 days, - NamespacePrefix: nsPre, - Test: o.t, + TTL: time.Hour * 720, // 30 days, + NamespacePrefix: nsPre, + Test: o.t, + PreventPodEviction: true, } - cd, err := chainlink.NewDeployment(6, map[string]any{ - "toml": client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customChainlinkNetworkTOML, network), + cd := chainlink.New(0, map[string]any{ + "replicas": 6, + "toml": client.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, }) - require.NoError(o.t, err, "Error creating chainlink deployment") + testEnvironment := environment.New(baseEnvironmentConfig). AddHelm(mockservercfg.New(nil)). AddHelm(mockserver.New(nil)). @@ -151,8 +155,8 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { Simulated: network.Simulated, WsURLs: network.URLs, })). - AddHelmCharts(cd) - err = testEnvironment.Run() + AddHelm(cd) + err := testEnvironment.Run() require.NoError(o.t, err, "Error launching test environment") o.testEnvironment = testEnvironment o.namespace = testEnvironment.Cfg.Namespace @@ -358,7 +362,7 @@ func (o *OCRSoakTest) LoadState() error { } testState := &OCRSoakTestState{} - saveData, err := ioutil.ReadFile(saveFileLocation) + saveData, err := os.ReadFile(saveFileLocation) if err != nil { return err } @@ -485,7 +489,7 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { o.log.Error().Err(err).Msg("Error saving state") } o.log.Warn().Str("Time Taken", time.Since(saveStart).String()).Msg("Saved state") - os.Exit(2) // Exit with code 2 to indicate test was interrupted, not just a normal failure + os.Exit(interruptedExitCode) // Exit with interrupted code to indicate test was interrupted, not just a normal failure case <-endTest: return case <-newRoundTrigger.C: @@ -555,14 +559,13 @@ func (o *OCRSoakTest) setFilterQuery() { func (o *OCRSoakTest) observeOCREvents() error { eventLogs := make(chan types.Log) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() eventSub, err := o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) + cancel() if err != nil { return err } go func() { - defer cancel() for { select { case event := <-eventLogs: @@ -582,13 +585,20 @@ func (o *OCRSoakTest) observeOCREvents() error { Int64("Answer", answerUpdated.Current.Int64()). Msg("Answer Updated Event") case err = <-eventSub.Err(): + backoff := time.Second for err != nil { o.log.Info(). Err(err). + Str("Backoff", backoff.String()). Interface("Query", o.filterQuery). Msg("Error while subscribed to OCR Logs. Resubscribing") - ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel = context.WithTimeout(context.Background(), backoff) eventSub, err = o.chainClient.SubscribeFilterLogs(ctx, o.filterQuery, eventLogs) + cancel() + if err != nil { + time.Sleep(backoff) + backoff = time.Duration(math.Min(float64(backoff)*2, float64(30*time.Second))) + } } } } diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index 3702d11745f..37047cdb667 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -9,6 +9,8 @@ import ( "go.uber.org/zap/zapcore" + "github.com/segmentio/ksuid" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/v2/core/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" @@ -113,18 +115,34 @@ func WithP2Pv1() NodeConfigOpt { ListenIP: utils2.MustIP("0.0.0.0"), ListenPort: utils2.Ptr[uint16](6690), } + // disabled default + c.P2P.V2 = toml.P2PV2{Enabled: utils2.Ptr(false)} } } func WithP2Pv2() NodeConfigOpt { return func(c *chainlink.Config) { c.P2P.V2 = toml.P2PV2{ - Enabled: utils2.Ptr(true), ListenAddresses: &[]string{"0.0.0.0:6690"}, } } } +func WithTracing() NodeConfigOpt { + return func(c *chainlink.Config) { + c.Tracing = toml.Tracing{ + Enabled: utils2.Ptr(true), + CollectorTarget: utils2.Ptr("otel-collector:4317"), + // ksortable unique id + NodeID: utils2.Ptr(ksuid.New().String()), + Attributes: map[string]string{ + "env": "smoke", + }, + SamplingRatio: utils2.Ptr(1.0), + } + } +} + func SetChainConfig( cfg *chainlink.Config, wsUrls, diff --git a/integration-tests/types/config/node/defaults/sample.toml b/integration-tests/types/config/node/defaults/sample.toml index 3663998003c..b0e1bc2a07d 100644 --- a/integration-tests/types/config/node/defaults/sample.toml +++ b/integration-tests/types/config/node/defaults/sample.toml @@ -15,7 +15,6 @@ DefaultTransactionQueueDepth = 0 [P2P] [P2P.V2] -Enabled = true ListenAddresses = ['0.0.0.0:6690'] AnnounceAddresses = ['0.0.0.0:6690'] DeltaDial = '500ms' diff --git a/integration-tests/utils/templates/secrets.go b/integration-tests/utils/templates/secrets.go index 3d3f9e44a90..f81287e871f 100644 --- a/integration-tests/utils/templates/secrets.go +++ b/integration-tests/utils/templates/secrets.go @@ -8,10 +8,11 @@ import ( // NodeSecretsTemplate are used as text templates because of secret redacted fields of chainlink.Secrets // secret fields can't be marshalled as a plain text type NodeSecretsTemplate struct { - PgDbName string - PgHost string - PgPort string - PgPassword string + PgDbName string + PgHost string + PgPort string + PgPassword string + CustomSecrets string } func (c NodeSecretsTemplate) String() (string, error) { @@ -22,11 +23,14 @@ URL = 'postgresql://postgres:{{ .PgPassword }}@{{ .PgHost }}:{{ .PgPort }}/{{ .P [Password] Keystore = '................' # Required +{{ if .CustomSecrets }} + {{ .CustomSecrets }} +{{ else }} [Mercury.Credentials.cred1] -# URL = 'http://host.docker.internal:3000/reports' URL = 'localhost:1338' Username = 'node' Password = 'nodepass' +{{ end }} ` return templates.MarshalTemplate(c, uuid.NewString(), tpl) } diff --git a/operator_ui/TAG b/operator_ui/TAG index 6762dd4e0f7..e08ca072670 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-a8fbbb3 +v0.8.0-e10948a diff --git a/plugins/README.md b/plugins/README.md index 73c39c6c94d..35d6af7f637 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -6,9 +6,9 @@ This directory supports Local-Out-Of-Process (LOOP) Plugins, an alternative node separate processes, plug-in via [github.com/hashicorp/go-plugin](https://github.com/hashicorp/go-plugin), and communicate via [GRPC](https://grpc.io). -There are currently two kinds of plugins, and one implementation of each: a Solana Relayer plugin, and a Median Reporting -plugin. The [cmd](cmd) directory contains their `package main`s for now. These can be built via `make install-solana` and -`make install-median`. +There are currently two kinds of plugins: Relayer plugins, and a Median product plugin. The [cmd](cmd) directory contains +some `package main`s while we transition, and they can be built via `make install-`. Solana & Starknet has been +moved to their respective repos, and all must be moved out of this module eventually. ## How to use diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index 6f713e078af..001ee30bf74 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -16,9 +16,24 @@ COPY . . # Build the golang binaries RUN make install-chainlink -RUN make install-solana +# Build LOOP Plugins RUN make install-median -RUN make install-starknet + +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana +RUN mkdir /chainlink-starknet +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/relayer | xargs -I % ln -s % /chainlink-starknet/relayer + +# Build image: Plugins +FROM golang:1.21-bullseye as buildplugins +RUN go version + +WORKDIR /chainlink-solana +COPY --from=buildgo /chainlink-solana . +RUN go install ./pkg/solana/cmd/chainlink-solana + +WORKDIR /chainlink-starknet/relayer +COPY --from=buildgo /chainlink-starknet/relayer . +RUN go install ./pkg/chainlink/cmd/chainlink-starknet # Final image: ubuntu with chainlink binary FROM ubuntu:20.04 @@ -34,11 +49,12 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && apt-get clean all COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ -COPY --from=buildgo /go/bin/chainlink-solana /usr/local/bin/ -ENV CL_SOLANA_CMD chainlink-solana COPY --from=buildgo /go/bin/chainlink-median /usr/local/bin/ ENV CL_MEDIAN_CMD chainlink-median -COPY --from=buildgo /go/bin/chainlink-starknet /usr/local/bin/ + +COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/ +ENV CL_SOLANA_CMD chainlink-solana +COPY --from=buildplugins /go/bin/chainlink-starknet /usr/local/bin/ ENV CL_STARKNET_CMD chainlink-starknet # Dependency of CosmWasm/wasmd diff --git a/plugins/cmd/chainlink-median/main.go b/plugins/cmd/chainlink-median/main.go index 00836fa7c24..87815d24d99 100644 --- a/plugins/cmd/chainlink-median/main.go +++ b/plugins/cmd/chainlink-median/main.go @@ -6,7 +6,6 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median" - "github.com/smartcontractkit/chainlink/v2/plugins" ) const ( @@ -14,7 +13,7 @@ const ( ) func main() { - s := plugins.MustNewStartedServer(loggerName) + s := loop.MustNewStartedServer(loggerName) defer s.Stop() p := median.NewPlugin(s.Logger) diff --git a/plugins/cmd/chainlink-solana/main.go b/plugins/cmd/chainlink-solana/main.go deleted file mode 100644 index ec30fa59f41..00000000000 --- a/plugins/cmd/chainlink-solana/main.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/go-plugin" - "github.com/pelletier/go-toml/v2" - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - pkgsol "github.com/smartcontractkit/chainlink-solana/pkg/solana" - - "github.com/smartcontractkit/chainlink/v2/core/chains/solana" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/plugins" -) - -const ( - loggerName = "PluginSolana" -) - -func main() { - s := plugins.MustNewStartedServer(loggerName) - defer s.Stop() - - p := &pluginRelayer{Base: plugins.Base{Logger: s.Logger}} - defer s.Logger.ErrorIfFn(p.Close, "Failed to close") - - s.MustRegister(p) - - stopCh := make(chan struct{}) - defer close(stopCh) - - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: loop.PluginRelayerHandshakeConfig(), - Plugins: map[string]plugin.Plugin{ - loop.PluginRelayerName: &loop.GRPCPluginRelayer{ - PluginServer: p, - BrokerConfig: loop.BrokerConfig{ - StopCh: stopCh, - Logger: s.Logger, - GRPCOpts: s.GRPCOpts, - }, - }, - }, - GRPCServer: s.GRPCOpts.NewServer, - }) -} - -type pluginRelayer struct { - plugins.Base -} - -func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, keystore loop.Keystore) (loop.Relayer, error) { - d := toml.NewDecoder(strings.NewReader(config)) - d.DisallowUnknownFields() - var cfg struct { - Solana solana.SolanaConfig - } - - if err := d.Decode(&cfg); err != nil { - return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) - } - - opts := solana.ChainOpts{ - Logger: c.Logger, - KeyStore: keystore, - } - chain, err := solana.NewChain(&cfg.Solana, opts) - if err != nil { - return nil, fmt.Errorf("failed to create chain: %w", err) - } - ra := relay.NewRelayerAdapter(pkgsol.NewRelayer(c.Logger, chain), chain) - - c.SubService(ra) - - return ra, nil -} diff --git a/plugins/cmd/chainlink-starknet/README.md b/plugins/cmd/chainlink-starknet/README.md deleted file mode 100644 index efeb5221db2..00000000000 --- a/plugins/cmd/chainlink-starknet/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# Staknet LOOP Plugin - -:warning: WIP, Experimental :warning: - -## Background - -This README is a temporary stop gap to capture the design design choices in the starknet stack that -are not obvious from reading the code. - -For information about LOOP Plugings in general, see `plugins/README.md` and the CLIP - -## LOOP Relayer summary - -For our purposes, the key points about LOOP Plugins are: - -- Node configuration determines which LOOPps are launched -- Orchestration between the node and LOOPps is facilitated by a common api - - Each LOOPp implementation needs to implements a factory function that instatates a LOOPp-specific implementation of the api - - The factory function itself is part of the api and therefore must have a common signature amongst all LOOPp implementations -- Each LOOPp relayer implementation must be able to sign transactions -- *All of the above imply a requirement for a common, abstract keystore in the node-LOOPp API* - -### Starknet Signing - -The existing `caigo` library passes around private keys in it's API. An explicit private key is required to create an `account` and -an `account` is needed to `Sign` a transaction. - -Given this, and the requirement above, our choices are -- Expose private keys via our abstract keystore -- Change `caigo` -- ? something else that I haven't thought about... open to ideas - -Exposing private keys is both an anti-pattern and a long term risk that we want to avoid. As such, we have choosen to change `caigo`. -By happenstance, we already support our own private fork of `caigo` so there is less friction to implementing this kind of change. - -#### Keystore design - -There are three layers to the problem, starting at the top of the stack: - -1. The starknet LOOPp implementation must implement a factory functions that accepts the abstract keystore, as discussed above -2. The starknet transaction manager must be changed to operate with this new keystore interface -3. `caigo` must expose an API that the transaction manager can use without requiring explicit private keys - -At the top of the stack, the abstract keystore, everything is bytes. This enables it to be generic and implementable in each LOOPp. At the -bottom of the stack, `caigo` the signature algorithms use a `*big.Int` types as dictated by the starknet curve. Given these observations, -the most natural layering is to change `caigo` to support a Keystore that operates on `*big.Int` and use our Transaction Manager -implementation to adapt from the generic LOOPp Keystore to the specific `caigo` Keystore. - - -```mermaid -classDiagram - -class caigo_Keystore{ - Sign(senderAddr string , msgHash *big.Int) (*big.Int, *big.Int,error) - } -class caigo_Account { - ... - caigo.Keystore -} -class loopp_Keystore{ - Sign(id string, data []byte) ([]byte,error) - } - -class starknet_KeystoreAdapter{ - looppKS loop.Keystore - +Sign(senderAddr string , msgHash *big.Int) (*big.Int, *big.Int,error) -} -note for starknet_KeystoreAdapter "responsible for translating from -generic LOOPp interface (bytes) to -caigo interface (*big.Int)" - -caigo_Keystore <|-- starknet_KeystoreAdapter : implements -loopp_Keystore *-- starknet_KeystoreAdapter : composition -caigo_Keystore *-- caigo_Account : composition - -``` diff --git a/plugins/cmd/chainlink-starknet/main.go b/plugins/cmd/chainlink-starknet/main.go deleted file mode 100644 index 1052f3c1fc6..00000000000 --- a/plugins/cmd/chainlink-starknet/main.go +++ /dev/null @@ -1,83 +0,0 @@ -package main - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/go-plugin" - "github.com/pelletier/go-toml/v2" - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink" - - "github.com/smartcontractkit/chainlink/v2/core/chains/starknet" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/plugins" -) - -const ( - loggerName = "PluginStarknet" -) - -func main() { - s := plugins.MustNewStartedServer(loggerName) - defer s.Stop() - - p := &pluginRelayer{Base: plugins.Base{Logger: s.Logger}} - defer s.Logger.ErrorIfFn(p.Close, "Failed to close") - - s.MustRegister(p) - - stopCh := make(chan struct{}) - defer close(stopCh) - - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: loop.PluginRelayerHandshakeConfig(), - Plugins: map[string]plugin.Plugin{ - loop.PluginRelayerName: &loop.GRPCPluginRelayer{ - PluginServer: p, - BrokerConfig: loop.BrokerConfig{ - StopCh: stopCh, - Logger: s.Logger, - GRPCOpts: s.GRPCOpts, - }, - }, - }, - GRPCServer: s.GRPCOpts.NewServer, - }) -} - -type pluginRelayer struct { - plugins.Base -} - -// NewRelayer implements the Loopp factory method used by the Loopp server to instantiate a starknet relayer -// [github.com/smartcontractkit/chainlink-relay/pkg/loop.PluginRelayer] -// loopKs must be an implementation that can construct a starknet keystore adapter -// [github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm.NewKeystoreAdapter] -func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, loopKs loop.Keystore) (loop.Relayer, error) { - d := toml.NewDecoder(strings.NewReader(config)) - d.DisallowUnknownFields() - var cfg struct { - Starknet starknet.StarknetConfig - } - if err := d.Decode(&cfg); err != nil { - return nil, fmt.Errorf("failed to decode config toml: %w:\n\t%s", err, config) - } - - opts := starknet.ChainOpts{ - Logger: c.Logger, - KeyStore: loopKs, - } - - chain, err := starknet.NewChain(&cfg.Starknet, opts) - if err != nil { - return nil, fmt.Errorf("failed to create chain: %w", err) - } - ra := relay.NewRelayerAdapter(pkgstarknet.NewRelayer(c.Logger, chain), chain) - - c.SubService(ra) - - return ra, nil -} diff --git a/plugins/config.go b/plugins/config.go index 13266410d2d..938cfd0d00c 100644 --- a/plugins/config.go +++ b/plugins/config.go @@ -1,10 +1,7 @@ package plugins import ( - "fmt" - "os" "os/exec" - "strconv" "github.com/smartcontractkit/chainlink-relay/pkg/loop" ) @@ -40,48 +37,3 @@ func (pc *registarConfig) RegisterLOOP(loopID string, cmdName string) (func() *e } return cmdFn, pc.grpcOpts, nil } - -// EnvConfig is the configuration interface between the application and the LOOP executable. The values -// are fully resolved and static and passed via the environment. -type EnvConfig interface { - PrometheusPort() int -} - -// SetCmdEnvFromConfig sets LOOP-specific vars in the env of the given cmd. -func SetCmdEnvFromConfig(cmd *exec.Cmd, cfg EnvConfig) { - forward := func(name string) { - if v, ok := os.LookupEnv(name); ok { - cmd.Env = append(cmd.Env, name+"="+v) - } - } - forward("CL_LOG_SQL_MIGRATIONS") - cmd.Env = append(cmd.Env, - "CL_PROMETHEUS_PORT="+strconv.FormatInt(int64(cfg.PrometheusPort()), 10), - ) -} - -// GetEnvConfig deserializes LOOP-specific environment variables to an EnvConfig -func GetEnvConfig() (EnvConfig, error) { - promPortStr := os.Getenv("CL_PROMETHEUS_PORT") - promPort, err := strconv.Atoi(promPortStr) - if err != nil { - return nil, fmt.Errorf("failed to parse CL_PROMETHEUS_PORT = %q: %w", promPortStr, err) - } - - return NewEnvConfig(promPort), nil -} - -// envConfig is an implementation of EnvConfig. -type envConfig struct { - prometheusPort int -} - -func NewEnvConfig(prometheusPort int) EnvConfig { - return &envConfig{ - prometheusPort: prometheusPort, - } -} - -func (e *envConfig) PrometheusPort() int { - return e.prometheusPort -} diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index c8bab8a9949..f402fc6fa17 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -6,6 +6,9 @@ import ( "sync" "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + + "github.com/smartcontractkit/chainlink/v2/core/config" ) const ( @@ -16,22 +19,24 @@ var ErrExists = errors.New("plugin already registered") type RegisteredLoop struct { Name string - EnvCfg EnvConfig + EnvCfg loop.EnvConfig } // LoopRegistry is responsible for assigning ports to plugins that are to be used for the -// plugin's prometheus HTTP server +// plugin's prometheus HTTP server, and for passing the tracing configuration to the plugin. type LoopRegistry struct { mu sync.Mutex registry map[string]*RegisteredLoop - lggr logger.Logger + lggr logger.Logger + cfgTracing config.Tracing } -func NewLoopRegistry(lggr logger.Logger) *LoopRegistry { +func NewLoopRegistry(lggr logger.Logger, tracingConfig config.Tracing) *LoopRegistry { return &LoopRegistry{ - registry: map[string]*RegisteredLoop{}, - lggr: logger.Named(lggr, "LoopRegistry"), + registry: map[string]*RegisteredLoop{}, + lggr: logger.Named(lggr, "LoopRegistry"), + cfgTracing: tracingConfig, } } @@ -45,10 +50,17 @@ func (m *LoopRegistry) Register(id string) (*RegisteredLoop, error) { return nil, ErrExists } nextPort := pluginDefaultPort + len(m.registry) - envCfg := NewEnvConfig(nextPort) + envCfg := loop.EnvConfig{PrometheusPort: nextPort} + + if m.cfgTracing != nil { + envCfg.TracingEnabled = m.cfgTracing.Enabled() + envCfg.TracingCollectorTarget = m.cfgTracing.CollectorTarget() + envCfg.TracingAttributes = m.cfgTracing.Attributes() + envCfg.TracingSamplingRatio = m.cfgTracing.SamplingRatio() + } m.registry[id] = &RegisteredLoop{Name: id, EnvCfg: envCfg} - m.lggr.Debugf("Registered loopp %q with config %v, port %d", id, envCfg, envCfg.PrometheusPort()) + m.lggr.Debugf("Registered loopp %q with config %v, port %d", id, envCfg, envCfg.PrometheusPort) return m.registry[id], nil } diff --git a/plugins/loop_registry_test.go b/plugins/loop_registry_test.go index 7e71c0f0574..b5da9154b68 100644 --- a/plugins/loop_registry_test.go +++ b/plugins/loop_registry_test.go @@ -1,4 +1,4 @@ -package plugins_test +package plugins import ( "testing" @@ -6,23 +6,54 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/plugins" ) func TestPluginPortManager(t *testing.T) { // register one - m := plugins.NewLoopRegistry(logger.TestLogger(t)) + m := NewLoopRegistry(logger.TestLogger(t), nil) pFoo, err := m.Register("foo") require.NoError(t, err) require.Equal(t, "foo", pFoo.Name) - require.Greater(t, pFoo.EnvCfg.PrometheusPort(), 0) + require.Greater(t, pFoo.EnvCfg.PrometheusPort, 0) // test duplicate pNil, err := m.Register("foo") - require.ErrorIs(t, err, plugins.ErrExists) + require.ErrorIs(t, err, ErrExists) require.Nil(t, pNil) // ensure increasing port assignment pBar, err := m.Register("bar") require.NoError(t, err) require.Equal(t, "bar", pBar.Name) - require.Equal(t, pFoo.EnvCfg.PrometheusPort()+1, pBar.EnvCfg.PrometheusPort()) + require.Equal(t, pFoo.EnvCfg.PrometheusPort+1, pBar.EnvCfg.PrometheusPort) +} + +// Mock tracing config +type MockCfgTracing struct{} + +func (m *MockCfgTracing) Enabled() bool { return true } +func (m *MockCfgTracing) CollectorTarget() string { return "http://localhost:9000" } +func (m *MockCfgTracing) Attributes() map[string]string { + return map[string]string{"attribute": "value"} +} +func (m *MockCfgTracing) SamplingRatio() float64 { return 0.1 } +func (m *MockCfgTracing) NodeID() string { return "" } + +func TestLoopRegistry_Register(t *testing.T) { + mockCfgTracing := &MockCfgTracing{} + registry := make(map[string]*RegisteredLoop) + + // Create a LoopRegistry instance with mockCfgTracing + loopRegistry := &LoopRegistry{ + lggr: logger.TestLogger(t), + registry: registry, + cfgTracing: mockCfgTracing, + } + + // Test case 1: Register new loop + registeredLoop, err := loopRegistry.Register("testID") + require.Nil(t, err) + require.Equal(t, "testID", registeredLoop.Name) + require.True(t, registeredLoop.EnvCfg.TracingEnabled) + require.Equal(t, "http://localhost:9000", registeredLoop.EnvCfg.TracingCollectorTarget) + require.Equal(t, map[string]string{"attribute": "value"}, registeredLoop.EnvCfg.TracingAttributes) + require.Equal(t, 0.1, registeredLoop.EnvCfg.TracingSamplingRatio) } diff --git a/plugins/plugin.go b/plugins/plugin.go deleted file mode 100644 index 0b93ef26f5c..00000000000 --- a/plugins/plugin.go +++ /dev/null @@ -1,44 +0,0 @@ -package plugins - -import ( - "sync" - - "golang.org/x/exp/maps" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/services" -) - -// Base is a base layer for plugins to easily manage sub-[types.Service]s. -type Base struct { - Logger logger.Logger - - mu sync.RWMutex - srvs []types.Service -} - -func (p *Base) Ready() error { return nil } -func (p *Base) Name() string { return p.Logger.Name() } - -func (p *Base) SubService(s types.Service) { - p.mu.Lock() - p.srvs = append(p.srvs, s) - p.mu.Unlock() -} - -func (p *Base) HealthReport() map[string]error { - hr := map[string]error{p.Name(): nil} - p.mu.RLock() - defer p.mu.RUnlock() - for _, s := range p.srvs { - maps.Copy(hr, s.HealthReport()) - } - return hr -} - -func (p *Base) Close() (err error) { - p.mu.RLock() - defer p.mu.RUnlock() - return services.MultiCloser(p.srvs).Close() -} diff --git a/plugins/prom.go b/plugins/prom.go deleted file mode 100644 index cf7fdf0e41b..00000000000 --- a/plugins/prom.go +++ /dev/null @@ -1,124 +0,0 @@ -package plugins - -import ( - "errors" - "fmt" - "net" - "net/http" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "golang.org/x/net/context" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" -) - -type PromServer struct { - port int - srvrDone chan struct{} // closed when the http server is done - srvr *http.Server - tcpListener *net.TCPListener - lggr logger.Logger - - handler http.Handler -} - -type PromServerOpt func(*PromServer) - -func WithHandler(h http.Handler) PromServerOpt { - return func(s *PromServer) { - s.handler = h - } -} - -func NewPromServer(port int, lggr logger.Logger, opts ...PromServerOpt) *PromServer { - - s := &PromServer{ - port: port, - lggr: lggr, - srvrDone: make(chan struct{}), - srvr: &http.Server{ - // reasonable default based on typical prom poll interval of 15s. - ReadTimeout: 5 * time.Second, - }, - - handler: promhttp.HandlerFor( - prometheus.DefaultGatherer, - promhttp.HandlerOpts{ - EnableOpenMetrics: true, - }, - ), - } - - for _, opt := range opts { - opt(s) - } - - return s -} - -// Start start HTTP server on specified port to handle metrics requests -func (p *PromServer) Start() error { - p.lggr.Debugf("Starting prom server on port %d", p.port) - err := p.setupListener() - if err != nil { - return err - } - - http.Handle("/metrics", p.handler) - - go func() { - defer close(p.srvrDone) - err := p.srvr.Serve(p.tcpListener) - if errors.Is(err, net.ErrClosed) { - // ErrClose is expected on gracefully shutdown - p.lggr.Warnf("%s closed", p.Name()) - } else { - p.lggr.Errorf("%s: %s", p.Name(), err) - } - - }() - return nil -} - -// Close shutdowns down the underlying HTTP server. See [http.Server.Close] for details -func (p *PromServer) Close() error { - err := p.srvr.Shutdown(context.Background()) - <-p.srvrDone - return err -} - -// Name of the server -func (p *PromServer) Name() string { - return fmt.Sprintf("%s-prom-server", p.lggr.Name()) -} - -// Port is the resolved port and is only known after Start(). -// returns -1 before it is resolved or if there was an error during resolution. -func (p *PromServer) Port() int { - if p.tcpListener == nil { - return -1 - } - // always safe to cast because we explicitly have a tcp listener - // there is direct access to Port without the addr casting - // Note: addr `:0` is not resolved to non-zero port until ListenTCP is called - // net.ResolveTCPAddr sounds promising, but doesn't work in practice - return p.tcpListener.Addr().(*net.TCPAddr).Port - -} - -// setupListener creates explicit listener so that we can resolve `:0` port, which is needed for testing -// if we didn't need the resolved addr, or could pick a static port we could use p.srvr.ListenAndServer -func (p *PromServer) setupListener() error { - - l, err := net.ListenTCP("tcp", &net.TCPAddr{ - Port: p.port, - }) - if err != nil { - return err - } - - p.tcpListener = l - return nil -} diff --git a/plugins/prom_test.go b/plugins/prom_test.go deleted file mode 100644 index 39ecca6931b..00000000000 --- a/plugins/prom_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package plugins - -import ( - "fmt" - "io" - "net/http" - "testing" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" -) - -func TestPromServer(t *testing.T) { - - testReg := prometheus.NewRegistry() - testHandler := promhttp.HandlerFor(testReg, promhttp.HandlerOpts{}) - testMetric := prometheus.NewCounter(prometheus.CounterOpts{ - Name: "test_metric", - }) - testReg.MustRegister(testMetric) - testMetric.Inc() - - s := NewPromServer(0, logger.Test(t), WithHandler(testHandler)) - // check that port is not resolved yet - require.Equal(t, -1, s.Port()) - require.NoError(t, s.Start()) - - url := fmt.Sprintf("http://localhost:%d/metrics", s.Port()) - resp, err := http.Get(url) //nolint - require.NoError(t, err) - require.NoError(t, err, "endpoint %s", url) - require.NotNil(t, resp.Body) - b, err := io.ReadAll(resp.Body) - require.NoError(t, err) - require.Contains(t, string(b), "test_metric") - defer resp.Body.Close() - - require.NoError(t, s.Close()) -} diff --git a/plugins/server.go b/plugins/server.go deleted file mode 100644 index b1d43612480..00000000000 --- a/plugins/server.go +++ /dev/null @@ -1,100 +0,0 @@ -package plugins - -import ( - "fmt" - "os" - - "github.com/smartcontractkit/chainlink-relay/pkg/logger" - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - "github.com/smartcontractkit/chainlink/v2/core/services" -) - -// NewStartedServer returns a started Server. -// The caller is responsible for calling Server.Stop(). -func NewStartedServer(loggerName string) (*Server, error) { - s, err := newServer(loggerName) - if err != nil { - return nil, err - } - err = s.start() - if err != nil { - return nil, err - } - - return s, nil -} - -// MustNewStartedServer returns a new started Server like NewStartedServer, but logs and exits in the event of error. -// The caller is responsible for calling Server.Stop(). -func MustNewStartedServer(loggerName string) *Server { - s, err := newServer(loggerName) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to start server: %s\n", err) - os.Exit(1) - } - err = s.start() - if err != nil { - s.Logger.Fatalf("Failed to start server: %s", err) - } - - return s -} - -// Server holds common plugin server fields. -type Server struct { - loop.GRPCOpts - Logger logger.SugaredLogger - *PromServer - services.Checker -} - -func newServer(loggerName string) (*Server, error) { - s := &Server{ - // default prometheus.Registerer - GRPCOpts: loop.SetupTelemetry(nil), - } - - lggr, err := loop.NewLogger() - if err != nil { - return nil, fmt.Errorf("error creating logger: %s", err) - } - lggr = logger.Named(lggr, loggerName) - s.Logger = logger.Sugared(lggr) - return s, nil -} - -func (s *Server) start() error { - envCfg, err := GetEnvConfig() - if err != nil { - return fmt.Errorf("error getting environment configuration: %w", err) - } - s.PromServer = NewPromServer(envCfg.PrometheusPort(), s.lggr) - err = s.PromServer.Start() - if err != nil { - return fmt.Errorf("error starting prometheus server: %w", err) - } - - s.Checker = services.NewChecker() - err = s.Checker.Start() - if err != nil { - return fmt.Errorf("error starting health checker: %w", err) - } - - return nil -} - -// MustRegister registers the Checkable with services.Checker, or exits upon failure. -func (s *Server) MustRegister(c services.Checkable) { - if err := s.Register(c); err != nil { - s.Logger.Fatalf("Failed to register %s with health checker: %v", c.Name(), err) - } -} - -// Stop closes resources and flushes logs. -func (s *Server) Stop() { - s.Logger.ErrorIfFn(s.Checker.Close, "Failed to close health checker") - s.Logger.ErrorIfFn(s.PromServer.Close, "Failed to close prometheus server") - if err := s.Logger.Sync(); err != nil { - fmt.Println("Failed to sync logger:", err) - } -} diff --git a/plugins/utils.go b/plugins/utils.go index fb251a96078..5e5e4142e86 100644 --- a/plugins/utils.go +++ b/plugins/utils.go @@ -19,7 +19,7 @@ func NewCmdFactory(register func(id string) (*RegisteredLoop, error), lcfg CmdCo } return func() *exec.Cmd { cmd := exec.Command(lcfg.Cmd) //#nosec G204 -- we control the value of the cmd so the lint/sec error is a false positive - SetCmdEnvFromConfig(cmd, registeredLoop.EnvCfg) + cmd.Env = append(cmd.Env, registeredLoop.EnvCfg.AsCmdEnv()...) return cmd }, nil } diff --git a/testdata/scripts/keys/eth/help.txtar b/testdata/scripts/keys/eth/help.txtar index 0484445580e..76db7cd5ae3 100644 --- a/testdata/scripts/keys/eth/help.txtar +++ b/testdata/scripts/keys/eth/help.txtar @@ -10,7 +10,7 @@ USAGE: COMMANDS: create Create a key in the node's keystore alongside the existing key; to create an original key, just run the node - list List available Ethereum accounts with their ETH & LINK balances, nonces, and other metadata + list List available Ethereum accounts with their ETH & LINK balances and other metadata delete Delete the ETH key by address (irreversible!) import Import an ETH key from a JSON file export Exports an ETH key to a JSON file diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 85b16edaa27..189476bfa84 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -47,13 +47,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -154,7 +154,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -167,7 +167,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -219,6 +219,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 5f02793ff57..593aa0b21d0 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -91,13 +91,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -263,6 +263,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -327,6 +333,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 527a739f7ca..7b8aa5e3836 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -91,13 +91,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -263,6 +263,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -327,6 +333,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 791a8aad076..ef6548619e1 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -91,13 +91,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -198,7 +198,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -211,7 +211,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -263,6 +263,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -327,6 +333,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index e9db92fb8f7..87b877bc882 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -81,13 +81,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -188,7 +188,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -201,7 +201,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -253,6 +253,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -317,6 +323,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index f48fa1926d8..c607da10644 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -88,13 +88,13 @@ LeaseRefreshInterval = '1s' [TelemetryIngress] UniConn = true Logging = false -ServerPubKey = '' -URL = '' BufferSize = 100 MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true +URL = '' +ServerPubKey = '' [AuditLogger] Enabled = false @@ -195,7 +195,7 @@ PeerID = '' TraceLogging = false [P2P.V1] -Enabled = true +Enabled = false AnnounceIP = '' AnnouncePort = 0 BootstrapCheckInterval = '20s' @@ -208,7 +208,7 @@ NewStreamTimeout = '10s' PeerstoreWriteInterval = '5m0s' [P2P.V2] -Enabled = false +Enabled = true AnnounceAddresses = [] DefaultBootstrappers = [] DeltaDial = '15s' @@ -260,6 +260,12 @@ OCRDevelopmentMode = false InfiniteDepthQueries = false DisableRateLimiting = false +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + [[EVM]] ChainID = '1' AutoCreateKey = true @@ -324,6 +330,7 @@ PollFailureThreshold = 5 PollInterval = '10s' SelectionMode = 'HighestHead' SyncThreshold = 5 +LeaseDuration = '0s' [EVM.OCR] ContractConfirmations = 4 diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar new file mode 100644 index 00000000000..ee7926f8f5f --- /dev/null +++ b/testdata/scripts/node/validate/warnings.txtar @@ -0,0 +1,279 @@ +exec chainlink node -c config.toml -s secrets.toml validate +cmp stdout out.txt + +-- config.toml -- +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +-- secrets.toml -- +[Database] +URL = 'postgresql://user:pass1234567890abcd@localhost:5432/dbname?sslmode=disable' + +[Password] +Keystore = 'keystore_pass' + +-- out.txt -- +# Secrets: +[Database] +URL = 'xxxxx' +AllowSimplePasswords = false + +[Password] +Keystore = 'xxxxx' + +# Input Configuration: +[P2P] +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +# Effective Configuration, with defaults applied: +InsecureFastScrypt = false +RootDir = '~/.chainlink' +ShutdownGracePeriod = '5s' + +[Feature] +FeedsManager = true +LogPoller = false +UICSAKeys = false + +[Database] +DefaultIdleInTxSessionTimeout = '1h0m0s' +DefaultLockTimeout = '15s' +DefaultQueryTimeout = '10s' +LogQueries = false +MaxIdleConns = 10 +MaxOpenConns = 20 +MigrateOnStartup = true + +[Database.Backup] +Dir = '' +Frequency = '1h0m0s' +Mode = 'none' +OnVersionUpgrade = true + +[Database.Listener] +MaxReconnectDuration = '10m0s' +MinReconnectInterval = '1m0s' +FallbackPollInterval = '30s' + +[Database.Lock] +Enabled = true +LeaseDuration = '10s' +LeaseRefreshInterval = '1s' + +[TelemetryIngress] +UniConn = true +Logging = false +BufferSize = 100 +MaxBatchSize = 50 +SendInterval = '500ms' +SendTimeout = '10s' +UseBatchSend = true +URL = '' +ServerPubKey = '' + +[AuditLogger] +Enabled = false +ForwardToUrl = '' +JsonWrapperKey = '' +Headers = [] + +[Log] +Level = 'info' +JSONConsole = false +UnixTS = false + +[Log.File] +Dir = '' +MaxSize = '5.12gb' +MaxAgeDays = 0 +MaxBackups = 1 + +[WebServer] +AllowOrigins = 'http://localhost:3000,http://localhost:6688' +BridgeResponseURL = '' +BridgeCacheTTL = '0s' +HTTPWriteTimeout = '10s' +HTTPPort = 6688 +SecureCookies = true +SessionTimeout = '15m0s' +SessionReaperExpiration = '240h0m0s' +HTTPMaxSize = '32.77kb' +StartTimeout = '15s' +ListenIP = '0.0.0.0' + +[WebServer.MFA] +RPID = '' +RPOrigin = '' + +[WebServer.RateLimit] +Authenticated = 1000 +AuthenticatedPeriod = '1m0s' +Unauthenticated = 5 +UnauthenticatedPeriod = '20s' + +[WebServer.TLS] +CertPath = '' +ForceRedirect = false +Host = '' +HTTPSPort = 6689 +KeyPath = '' +ListenIP = '0.0.0.0' + +[JobPipeline] +ExternalInitiatorsEnabled = false +MaxRunDuration = '10m0s' +MaxSuccessfulRuns = 10000 +ReaperInterval = '1h0m0s' +ReaperThreshold = '24h0m0s' +ResultWriteQueueDepth = 100 + +[JobPipeline.HTTPRequest] +DefaultTimeout = '15s' +MaxSize = '32.77kb' + +[FluxMonitor] +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false + +[OCR2] +Enabled = false +ContractConfirmations = 3 +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +ContractTransmitterTransmitTimeout = '10s' +DatabaseTimeout = '10s' +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +CaptureEATelemetry = false +CaptureAutomationCustomTelemetry = false +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false +TraceLogging = false + +[OCR] +Enabled = false +ObservationTimeout = '5s' +BlockchainTimeout = '20s' +ContractPollInterval = '1m0s' +ContractSubscribeInterval = '2m0s' +DefaultTransactionQueueDepth = 1 +KeyBundleID = '0000000000000000000000000000000000000000000000000000000000000000' +SimulateTransactions = false +TransmitterAddress = '' +CaptureEATelemetry = false +TraceLogging = false + +[P2P] +IncomingMessageBufferSize = 10 +OutgoingMessageBufferSize = 10 +PeerID = '' +TraceLogging = false + +[P2P.V1] +Enabled = true +AnnounceIP = '' +AnnouncePort = 0 +BootstrapCheckInterval = '20s' +DefaultBootstrapPeers = [] +DHTAnnouncementCounterUserPrefix = 0 +DHTLookupInterval = 10 +ListenIP = '0.0.0.0' +ListenPort = 0 +NewStreamTimeout = '10s' +PeerstoreWriteInterval = '5m0s' + +[P2P.V2] +Enabled = true +AnnounceAddresses = [] +DefaultBootstrappers = [] +DeltaDial = '15s' +DeltaReconcile = '1m0s' +ListenAddresses = [] + +[Keeper] +DefaultTransactionQueueDepth = 1 +GasPriceBufferPercent = 20 +GasTipCapBufferPercent = 20 +BaseFeeBufferPercent = 20 +MaxGracePeriod = 100 +TurnLookBack = 1000 + +[Keeper.Registry] +CheckGasOverhead = 200000 +PerformGasOverhead = 300000 +MaxPerformDataSize = 5000 +SyncInterval = '30m0s' +SyncUpkeepQueueSize = 10 + +[AutoPprof] +Enabled = false +ProfileRoot = '' +PollInterval = '10s' +GatherDuration = '10s' +GatherTraceDuration = '5s' +MaxProfileSize = '100.00mb' +CPUProfileRate = 1 +MemProfileRate = 1 +BlockProfileRate = 1 +MutexProfileFraction = 1 +MemThreshold = '4.00gb' +GoroutineThreshold = 5000 + +[Pyroscope] +ServerAddress = '' +Environment = 'mainnet' + +[Sentry] +Debug = false +DSN = '' +Environment = '' +Release = '' + +[Insecure] +DevWebServer = false +OCRDevelopmentMode = false +InfiniteDepthQueries = false +DisableRateLimiting = false + +[Tracing] +Enabled = false +CollectorTarget = '' +NodeID = '' +SamplingRatio = 0.0 + +# Configuration warning: +2 errors: + - P2P.V1: is deprecated and will be removed in a future version + - P2P.V1: 10 errors: + - AnnounceIP: is deprecated and will be removed in a future version + - AnnouncePort: is deprecated and will be removed in a future version + - BootstrapCheckInterval: is deprecated and will be removed in a future version + - DefaultBootstrapPeers: is deprecated and will be removed in a future version + - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version + - DHTLookupInterval: is deprecated and will be removed in a future version + - ListenIP: is deprecated and will be removed in a future version + - ListenPort: is deprecated and will be removed in a future version + - NewStreamTimeout: is deprecated and will be removed in a future version + - PeerstoreWriteInterval: is deprecated and will be removed in a future version +Valid configuration. diff --git a/tools/bin/go_core_race_tests b/tools/bin/go_core_race_tests index 81571bfbbe3..aa6510c1127 100755 --- a/tools/bin/go_core_race_tests +++ b/tools/bin/go_core_race_tests @@ -12,7 +12,7 @@ use_tee() { cat > "$@" fi } -GORACE="log_path=$PWD/race" go test -json -tags test -race -ldflags "$GO_LDFLAGS" -shuffle on -timeout "$TIMEOUT" -count "$COUNT" $1 | use_tee "$OUTPUT_FILE" +GORACE="log_path=$PWD/race" go test -json -race -ldflags "$GO_LDFLAGS" -shuffle on -timeout "$TIMEOUT" -count "$COUNT" $1 | use_tee "$OUTPUT_FILE" EXITCODE=${PIPESTATUS[0]} # Fail if any race logs are present. if ls race.* &>/dev/null diff --git a/tools/bin/go_core_tests b/tools/bin/go_core_tests index 79f7a480cfb..694a51d1f82 100755 --- a/tools/bin/go_core_tests +++ b/tools/bin/go_core_tests @@ -16,7 +16,7 @@ use_tee() { cat > "$@" fi } -go test -json -ldflags "$GO_LDFLAGS" -tags test,integration $TEST_FLAGS -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt $1 | use_tee $OUTPUT_FILE +go test -json -ldflags "$GO_LDFLAGS" -tags integration $TEST_FLAGS -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt $1 | use_tee $OUTPUT_FILE EXITCODE=${PIPESTATUS[0]} # Assert no known sensitive strings present in test logger output diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 8fa81db5ba0..c4509ff2cc9 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -232,12 +232,6 @@ func TestRunner_RootLevelTest(t *testing.T) { assert.True(t, ok) } -type exitError struct{} - -func (e *exitError) ExitCode() int { return 1 } - -func (e *exitError) Error() string { return "exit code: 1" } - func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/core/assets","Test":"TestLink","Elapsed":0}`